DEV messaging stage 2/4: In this stage all DEV commands are now being
[dragonfly.git] / sys / kern / kern_device.c
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.1 2003/07/22 17:03:33 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_init_port(port, NULL);
69     port->mp_beginmsg = 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_putport(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 EINPROGRESS).
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 != EINPROGRESS);
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->si_devsw)
179         return (dev->si_devsw);
180     return(cdevsw[major(dev)]);
181 }
182
183 static __inline
184 lwkt_port_t
185 _init_cdevmsg(dev_t dev, cdevmsg_t msg, int cmd)
186 {
187     struct cdevsw *csw;
188
189     lwkt_initmsg(&msg->msg, cmd);
190     msg->dev = dev;
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)]);
196         return(csw->d_port);
197     }
198     return(NULL);
199 }
200
201 int
202 dev_dopen(dev_t dev, int oflags, int devtype, thread_t td)
203 {
204     struct cdevmsg_open msg;
205     lwkt_port_t port;
206
207     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
208     if (port == NULL)
209         return(ENXIO);
210     msg.oflags = oflags;
211     msg.devtype = devtype;
212     msg.td = td;
213     return(lwkt_domsg(port, &msg.msg.msg));
214 }
215
216 int
217 dev_dclose(dev_t dev, int fflag, int devtype, thread_t td)
218 {
219     struct cdevmsg_close msg;
220     lwkt_port_t port;
221
222     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
223     if (port == NULL)
224         return(ENXIO);
225     msg.fflag = fflag;
226     msg.devtype = devtype;
227     msg.td = td;
228     return(lwkt_domsg(port, &msg.msg.msg));
229 }
230
231 void
232 dev_dstrategy(dev_t dev, struct buf *bp)
233 {
234     struct cdevmsg_strategy msg;
235     lwkt_port_t port;
236
237     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
238     KKASSERT(port);     /* 'nostrategy' function is NULL YYY */
239     msg.bp = bp;
240     lwkt_domsg(port, &msg.msg.msg);
241 }
242
243 int
244 dev_dioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
245 {
246     struct cdevmsg_ioctl msg;
247     lwkt_port_t port;
248
249     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
250     if (port == NULL)
251         return(ENXIO);
252     msg.cmd = cmd;
253     msg.data = data;
254     msg.fflag = fflag;
255     msg.td = td;
256     return(lwkt_domsg(port, &msg.msg.msg));
257 }
258
259 int
260 dev_ddump(dev_t dev)
261 {
262     struct cdevmsg_dump msg;
263     lwkt_port_t port;
264
265     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
266     if (port == NULL)
267         return(ENXIO);
268     return(lwkt_domsg(port, &msg.msg.msg));
269 }
270
271 int
272 dev_dpsize(dev_t dev)
273 {
274     struct cdevmsg_psize msg;
275     lwkt_port_t port;
276     int error;
277
278     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
279     if (port == NULL)
280         return(-1);
281     error = lwkt_domsg(port, &msg.msg.msg);
282     if (error == 0)
283         return(msg.result);
284     return(-1);
285 }
286
287 int
288 dev_dread(dev_t dev, struct uio *uio, int ioflag)
289 {
290     struct cdevmsg_read msg;
291     lwkt_port_t port;
292
293     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
294     if (port == NULL)
295         return(ENXIO);
296     msg.uio = uio;
297     msg.ioflag = ioflag;
298     return(lwkt_domsg(port, &msg.msg.msg));
299 }
300
301 int
302 dev_dwrite(dev_t dev, struct uio *uio, int ioflag)
303 {
304     struct cdevmsg_write msg;
305     lwkt_port_t port;
306
307     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
308     if (port == NULL)
309         return(ENXIO);
310     msg.uio = uio;
311     msg.ioflag = ioflag;
312     return(lwkt_domsg(port, &msg.msg.msg));
313 }
314
315 int
316 dev_dpoll(dev_t dev, int events, thread_t td)
317 {
318     struct cdevmsg_poll msg;
319     lwkt_port_t port;
320     int error;
321
322     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
323     if (port == NULL)
324         return(ENXIO);
325     msg.events = events;
326     msg.td = td;
327     error = lwkt_domsg(port, &msg.msg.msg);
328     if (error == 0)
329         return(msg.events);
330     return(seltrue(dev, msg.events, td));
331 }
332
333 int
334 dev_dkqfilter(dev_t dev, struct knote *kn)
335 {
336     struct cdevmsg_kqfilter msg;
337     lwkt_port_t port;
338     int error;
339
340     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
341     if (port == NULL)
342         return(ENXIO);
343     msg.kn = kn;
344     error = lwkt_domsg(port, &msg.msg.msg);
345     if (error == 0)
346         return(msg.result);
347     return(ENODEV);
348 }
349
350 int
351 dev_dmmap(dev_t dev, vm_offset_t offset, int nprot)
352 {
353     struct cdevmsg_mmap msg;
354     lwkt_port_t port;
355     int error;
356
357     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
358     if (port == NULL)
359         return(-1);
360     msg.offset = offset;
361     msg.nprot = nprot;
362     error = lwkt_domsg(port, &msg.msg.msg);
363     if (error == 0)
364         return(msg.result);
365     return(-1);
366 }
367
368 int
369 dev_port_dopen(lwkt_port_t port, dev_t dev, int oflags, int devtype, thread_t td)
370 {
371     struct cdevmsg_open msg;
372
373     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
374     if (port == NULL)
375         return(ENXIO);
376     msg.oflags = oflags;
377     msg.devtype = devtype;
378     msg.td = td;
379     return(lwkt_domsg(port, &msg.msg.msg));
380 }
381
382 int
383 dev_port_dclose(lwkt_port_t port, dev_t dev, int fflag, int devtype, thread_t td)
384 {
385     struct cdevmsg_close msg;
386
387     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
388     if (port == NULL)
389         return(ENXIO);
390     msg.fflag = fflag;
391     msg.devtype = devtype;
392     msg.td = td;
393     return(lwkt_domsg(port, &msg.msg.msg));
394 }
395
396 void
397 dev_port_dstrategy(lwkt_port_t port, dev_t dev, struct buf *bp)
398 {
399     struct cdevmsg_strategy msg;
400
401     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
402     KKASSERT(port);     /* 'nostrategy' function is NULL YYY */
403     msg.bp = bp;
404     lwkt_domsg(port, &msg.msg.msg);
405 }
406
407 int
408 dev_port_dioctl(lwkt_port_t port, dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
409 {
410     struct cdevmsg_ioctl msg;
411
412     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
413     if (port == NULL)
414         return(ENXIO);
415     msg.cmd = cmd;
416     msg.data = data;
417     msg.fflag = fflag;
418     msg.td = td;
419     return(lwkt_domsg(port, &msg.msg.msg));
420 }
421
422 int
423 dev_port_ddump(lwkt_port_t port, dev_t dev)
424 {
425     struct cdevmsg_dump msg;
426
427     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
428     if (port == NULL)
429         return(ENXIO);
430     return(lwkt_domsg(port, &msg.msg.msg));
431 }
432
433 int
434 dev_port_dpsize(lwkt_port_t port, dev_t dev)
435 {
436     struct cdevmsg_psize msg;
437     int error;
438
439     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
440     if (port == NULL)
441         return(-1);
442     error = lwkt_domsg(port, &msg.msg.msg);
443     if (error == 0)
444         return(msg.result);
445     return(-1);
446 }
447
448 int
449 dev_port_dread(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
450 {
451     struct cdevmsg_read msg;
452
453     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
454     if (port == NULL)
455         return(ENXIO);
456     msg.uio = uio;
457     msg.ioflag = ioflag;
458     return(lwkt_domsg(port, &msg.msg.msg));
459 }
460
461 int
462 dev_port_dwrite(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
463 {
464     struct cdevmsg_write msg;
465
466     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
467     if (port == NULL)
468         return(ENXIO);
469     msg.uio = uio;
470     msg.ioflag = ioflag;
471     return(lwkt_domsg(port, &msg.msg.msg));
472 }
473
474 int
475 dev_port_dpoll(lwkt_port_t port, dev_t dev, int events, thread_t td)
476 {
477     struct cdevmsg_poll msg;
478     int error;
479
480     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
481     if (port == NULL)
482         return(ENXIO);
483     msg.events = events;
484     msg.td = td;
485     error = lwkt_domsg(port, &msg.msg.msg);
486     if (error == 0)
487         return(msg.events);
488     return(seltrue(dev, msg.events, td));
489 }
490
491 int
492 dev_port_dkqfilter(lwkt_port_t port, dev_t dev, struct knote *kn)
493 {
494     struct cdevmsg_kqfilter msg;
495     int error;
496
497     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
498     if (port == NULL)
499         return(ENXIO);
500     msg.kn = kn;
501     error = lwkt_domsg(port, &msg.msg.msg);
502     if (error == 0)
503         return(msg.result);
504     return(ENODEV);
505 }
506
507 int
508 dev_port_dmmap(lwkt_port_t port, dev_t dev, vm_offset_t offset, int nprot)
509 {
510     struct cdevmsg_mmap msg;
511     int error;
512
513     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
514     if (port == NULL)
515         return(-1);
516     msg.offset = offset;
517     msg.nprot = nprot;
518     error = lwkt_domsg(port, &msg.msg.msg);
519     if (error == 0)
520         return(msg.result);
521     return(-1);
522 }
523
524 const char *
525 dev_dname(dev_t dev)
526 {
527     struct cdevsw *csw;
528
529     if ((csw = _devsw(dev)) != NULL)
530         return(csw->d_name);
531     return(NULL);
532 }
533
534 int
535 dev_dflags(dev_t dev)
536 {
537     struct cdevsw *csw;
538
539     if ((csw = _devsw(dev)) != NULL)
540         return(csw->d_flags);
541     return(NULL);
542 }
543
544 int
545 dev_dmaj(dev_t dev)
546 {
547     struct cdevsw *csw;
548
549     if ((csw = _devsw(dev)) != NULL)
550         return(csw->d_maj);
551     return(NULL);
552 }
553
554 lwkt_port_t
555 dev_dport(dev_t dev)
556 {
557     struct cdevsw *csw;
558
559     if ((csw = _devsw(dev)) != NULL) {
560         if (cdevport[major(dev)])       /* YYY too hackish */
561             return(cdevport[major(dev)]);
562         return(csw->d_port);
563     }
564     return(NULL);
565 }
566
567 #if 0
568 /*
569  * cdevsw[] array functions, moved from kern/kern_conf.c
570  */
571 struct cdevsw *
572 devsw(dev_t dev)
573 {
574     return(_devsw(dev));
575 }
576 #endif
577
578 /*
579  * Convert a cdevsw template into the real thing, filling in fields the
580  * device left empty with appropriate defaults.
581  */
582 void
583 compile_devsw(struct cdevsw *devsw)
584 {
585     static lwkt_port devsw_compat_port;
586
587     if (devsw_compat_port.mp_beginmsg == NULL)
588         init_default_cdevsw_port(&devsw_compat_port);
589     
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;
612
613     if (devsw->d_port == NULL)
614         devsw->d_port = &devsw_compat_port;
615 }
616
617 /*
618  * Add a cdevsw entry
619  */
620 int
621 cdevsw_add(struct cdevsw *newentry)
622 {
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);
627         return (EINVAL);
628     }
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);
632     }
633     cdevsw[newentry->d_maj] = newentry;
634     return (0);
635 }
636
637 /*
638  * Add a cdevsw entry and override the port.
639  */
640 lwkt_port_t
641 cdevsw_add_override(struct cdevsw *newentry, lwkt_port_t port)
642 {
643     int error;
644
645     if ((error = cdevsw_add(newentry)) == 0)
646         cdevport[newentry->d_maj] = port;
647     return(newentry->d_port);
648 }
649
650 lwkt_port_t
651 cdevsw_dev_override(dev_t dev, lwkt_port_t port)
652 {
653     struct cdevsw *csw;
654
655     KKASSERT(major(dev) >= 0 && major(dev) < NUMCDEVSW);
656     if ((csw = _devsw(dev)) != NULL) {
657         cdevport[major(dev)] = port;
658         return(csw->d_port);
659     }
660     return(NULL);
661 }
662
663 /*
664  *  Remove a cdevsw entry
665  */
666 int
667 cdevsw_remove(struct cdevsw *oldentry)
668 {
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);
672         return EINVAL;
673     }
674     cdevsw[oldentry->d_maj] = NULL;
675     cdevport[oldentry->d_maj] = NULL;
676     return 0;
677 }
678