Merge from vendor branch LESS:
[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.9 2004/04/20 01:52:22 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  * YYY NOTE: ms_cmd can now hold a function pointer, should this code be
66  * converted from an integer op to a function pointer with a flag to
67  * indicate legacy operation?
68  */
69 static void
70 init_default_cdevsw_port(lwkt_port_t port)
71 {
72     lwkt_initport(port, NULL);
73     port->mp_putport = cdevsw_putport;
74 }
75
76 static
77 int
78 cdevsw_putport(lwkt_port_t port, lwkt_msg_t lmsg)
79 {
80     cdevallmsg_t msg = (cdevallmsg_t)lmsg;
81     struct cdevsw *csw = msg->am_msg.csw;
82     int error;
83
84     /*
85      * If queueable then officially queue the message
86      */
87     if (port->mp_td) {
88         int mask = (1 << (msg->am_lmsg.ms_cmd.cm_op & MSG_SUBCMD_MASK));
89         if (csw->d_autoq & mask) 
90             return(lwkt_beginmsg(port, &msg->am_lmsg));
91     }
92
93     /*
94      * Run the device switch function synchronously in the context of the
95      * caller and return a synchronous error code (anything not EASYNC).
96      */
97     switch(msg->am_lmsg.ms_cmd.cm_op) {
98     case CDEV_CMD_OPEN:
99         error = csw->old_open(
100                     msg->am_open.msg.dev,
101                     msg->am_open.oflags,
102                     msg->am_open.devtype,
103                     msg->am_open.td);
104         break;
105     case CDEV_CMD_CLOSE:
106         error = csw->old_close(
107                     msg->am_close.msg.dev,
108                     msg->am_close.fflag,
109                     msg->am_close.devtype,
110                     msg->am_close.td);
111         break;
112     case CDEV_CMD_STRATEGY:
113         csw->old_strategy(msg->am_strategy.bp);
114         error = 0;
115         break;
116     case CDEV_CMD_IOCTL:
117         error = csw->old_ioctl(
118                     msg->am_ioctl.msg.dev,
119                     msg->am_ioctl.cmd,
120                     msg->am_ioctl.data,
121                     msg->am_ioctl.fflag,
122                     msg->am_ioctl.td);
123         break;
124     case CDEV_CMD_DUMP:
125         error = csw->old_dump(msg->am_ioctl.msg.dev);
126         break;
127     case CDEV_CMD_PSIZE:
128         msg->am_psize.result = csw->old_psize(msg->am_psize.msg.dev);
129         error = 0;      /* XXX */
130         break;
131     case CDEV_CMD_READ:
132         error = csw->old_read(
133                     msg->am_read.msg.dev,
134                     msg->am_read.uio,
135                     msg->am_read.ioflag);
136         break;
137     case CDEV_CMD_WRITE:
138         error = csw->old_write(
139                     msg->am_read.msg.dev,
140                     msg->am_read.uio,
141                     msg->am_read.ioflag);
142         break;
143     case CDEV_CMD_POLL:
144         msg->am_poll.events = csw->old_poll(
145                                 msg->am_poll.msg.dev,
146                                 msg->am_poll.events,
147                                 msg->am_poll.td);
148         error = 0;
149         break;
150     case CDEV_CMD_KQFILTER:
151         msg->am_kqfilter.result = csw->old_kqfilter(
152                                 msg->am_kqfilter.msg.dev,
153                                 msg->am_kqfilter.kn);
154         error = 0;
155         break;
156     case CDEV_CMD_MMAP:
157         msg->am_mmap.result = csw->old_mmap(
158                     msg->am_mmap.msg.dev,
159                     msg->am_mmap.offset,
160                     msg->am_mmap.nprot);
161         error = 0;      /* XXX */
162         break;
163     default:
164         error = ENOSYS;
165         break;
166     }
167     KKASSERT(error != EASYNC);
168     return(error);
169 }
170
171 /*
172  * These device dispatch functions provide convenient entry points for
173  * any code wishing to make a dev call.
174  *
175  * YYY we ought to be able to optimize the port lookup by caching it in
176  * the dev_t structure itself.
177  */
178 static __inline
179 struct cdevsw *
180 _devsw(dev_t dev)
181 {
182     if (dev == NULL)
183         return(NULL);
184     if (dev->si_devsw)
185         return (dev->si_devsw);
186     return(cdevsw[major(dev)]);
187 }
188
189 static __inline
190 lwkt_port_t
191 _init_cdevmsg(dev_t dev, cdevmsg_t msg, int cmd)
192 {
193     struct cdevsw *csw;
194
195     lwkt_initmsg_simple(&msg->msg, cmd);
196     msg->dev = dev;
197     msg->csw = csw = _devsw(dev);
198     if (csw != NULL) {                  /* YYY too hackish */
199         KKASSERT(csw->d_port);          /* YYY too hackish */
200         if (cdevport[major(dev)])       /* YYY too hackish */
201             return(cdevport[major(dev)]);
202         return(csw->d_port);
203     }
204     return(NULL);
205 }
206
207 int
208 dev_dopen(dev_t dev, int oflags, int devtype, thread_t td)
209 {
210     struct cdevmsg_open msg;
211     lwkt_port_t port;
212
213     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
214     if (port == NULL)
215         return(ENXIO);
216     msg.oflags = oflags;
217     msg.devtype = devtype;
218     msg.td = td;
219     return(lwkt_domsg(port, &msg.msg.msg));
220 }
221
222 int
223 dev_dclose(dev_t dev, int fflag, int devtype, thread_t td)
224 {
225     struct cdevmsg_close msg;
226     lwkt_port_t port;
227
228     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
229     if (port == NULL)
230         return(ENXIO);
231     msg.fflag = fflag;
232     msg.devtype = devtype;
233     msg.td = td;
234     return(lwkt_domsg(port, &msg.msg.msg));
235 }
236
237 void
238 dev_dstrategy(dev_t dev, struct buf *bp)
239 {
240     struct cdevmsg_strategy msg;
241     lwkt_port_t port;
242
243     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
244     KKASSERT(port);     /* 'nostrategy' function is NULL YYY */
245     msg.bp = bp;
246     lwkt_domsg(port, &msg.msg.msg);
247 }
248
249 int
250 dev_dioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
251 {
252     struct cdevmsg_ioctl msg;
253     lwkt_port_t port;
254
255     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
256     if (port == NULL)
257         return(ENXIO);
258     msg.cmd = cmd;
259     msg.data = data;
260     msg.fflag = fflag;
261     msg.td = td;
262     return(lwkt_domsg(port, &msg.msg.msg));
263 }
264
265 int
266 dev_ddump(dev_t dev)
267 {
268     struct cdevmsg_dump msg;
269     lwkt_port_t port;
270
271     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
272     if (port == NULL)
273         return(ENXIO);
274     return(lwkt_domsg(port, &msg.msg.msg));
275 }
276
277 int
278 dev_dpsize(dev_t dev)
279 {
280     struct cdevmsg_psize msg;
281     lwkt_port_t port;
282     int error;
283
284     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
285     if (port == NULL)
286         return(-1);
287     error = lwkt_domsg(port, &msg.msg.msg);
288     if (error == 0)
289         return(msg.result);
290     return(-1);
291 }
292
293 int
294 dev_dread(dev_t dev, struct uio *uio, int ioflag)
295 {
296     struct cdevmsg_read msg;
297     lwkt_port_t port;
298
299     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
300     if (port == NULL)
301         return(ENXIO);
302     msg.uio = uio;
303     msg.ioflag = ioflag;
304     return(lwkt_domsg(port, &msg.msg.msg));
305 }
306
307 int
308 dev_dwrite(dev_t dev, struct uio *uio, int ioflag)
309 {
310     struct cdevmsg_write msg;
311     lwkt_port_t port;
312
313     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
314     if (port == NULL)
315         return(ENXIO);
316     msg.uio = uio;
317     msg.ioflag = ioflag;
318     return(lwkt_domsg(port, &msg.msg.msg));
319 }
320
321 int
322 dev_dpoll(dev_t dev, int events, thread_t td)
323 {
324     struct cdevmsg_poll msg;
325     lwkt_port_t port;
326     int error;
327
328     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
329     if (port == NULL)
330         return(ENXIO);
331     msg.events = events;
332     msg.td = td;
333     error = lwkt_domsg(port, &msg.msg.msg);
334     if (error == 0)
335         return(msg.events);
336     return(seltrue(dev, msg.events, td));
337 }
338
339 int
340 dev_dkqfilter(dev_t dev, struct knote *kn)
341 {
342     struct cdevmsg_kqfilter msg;
343     lwkt_port_t port;
344     int error;
345
346     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
347     if (port == NULL)
348         return(ENXIO);
349     msg.kn = kn;
350     error = lwkt_domsg(port, &msg.msg.msg);
351     if (error == 0)
352         return(msg.result);
353     return(ENODEV);
354 }
355
356 int
357 dev_dmmap(dev_t dev, vm_offset_t offset, int nprot)
358 {
359     struct cdevmsg_mmap msg;
360     lwkt_port_t port;
361     int error;
362
363     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
364     if (port == NULL)
365         return(-1);
366     msg.offset = offset;
367     msg.nprot = nprot;
368     error = lwkt_domsg(port, &msg.msg.msg);
369     if (error == 0)
370         return(msg.result);
371     return(-1);
372 }
373
374 int
375 dev_port_dopen(lwkt_port_t port, dev_t dev, int oflags, int devtype, thread_t td)
376 {
377     struct cdevmsg_open msg;
378
379     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
380     if (port == NULL)
381         return(ENXIO);
382     msg.oflags = oflags;
383     msg.devtype = devtype;
384     msg.td = td;
385     return(lwkt_domsg(port, &msg.msg.msg));
386 }
387
388 int
389 dev_port_dclose(lwkt_port_t port, dev_t dev, int fflag, int devtype, thread_t td)
390 {
391     struct cdevmsg_close msg;
392
393     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
394     if (port == NULL)
395         return(ENXIO);
396     msg.fflag = fflag;
397     msg.devtype = devtype;
398     msg.td = td;
399     return(lwkt_domsg(port, &msg.msg.msg));
400 }
401
402 void
403 dev_port_dstrategy(lwkt_port_t port, dev_t dev, struct buf *bp)
404 {
405     struct cdevmsg_strategy msg;
406
407     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
408     KKASSERT(port);     /* 'nostrategy' function is NULL YYY */
409     msg.bp = bp;
410     lwkt_domsg(port, &msg.msg.msg);
411 }
412
413 int
414 dev_port_dioctl(lwkt_port_t port, dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
415 {
416     struct cdevmsg_ioctl msg;
417
418     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
419     if (port == NULL)
420         return(ENXIO);
421     msg.cmd = cmd;
422     msg.data = data;
423     msg.fflag = fflag;
424     msg.td = td;
425     return(lwkt_domsg(port, &msg.msg.msg));
426 }
427
428 int
429 dev_port_ddump(lwkt_port_t port, dev_t dev)
430 {
431     struct cdevmsg_dump msg;
432
433     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
434     if (port == NULL)
435         return(ENXIO);
436     return(lwkt_domsg(port, &msg.msg.msg));
437 }
438
439 int
440 dev_port_dpsize(lwkt_port_t port, dev_t dev)
441 {
442     struct cdevmsg_psize msg;
443     int error;
444
445     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
446     if (port == NULL)
447         return(-1);
448     error = lwkt_domsg(port, &msg.msg.msg);
449     if (error == 0)
450         return(msg.result);
451     return(-1);
452 }
453
454 int
455 dev_port_dread(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
456 {
457     struct cdevmsg_read msg;
458
459     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
460     if (port == NULL)
461         return(ENXIO);
462     msg.uio = uio;
463     msg.ioflag = ioflag;
464     return(lwkt_domsg(port, &msg.msg.msg));
465 }
466
467 int
468 dev_port_dwrite(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
469 {
470     struct cdevmsg_write msg;
471
472     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
473     if (port == NULL)
474         return(ENXIO);
475     msg.uio = uio;
476     msg.ioflag = ioflag;
477     return(lwkt_domsg(port, &msg.msg.msg));
478 }
479
480 int
481 dev_port_dpoll(lwkt_port_t port, dev_t dev, int events, thread_t td)
482 {
483     struct cdevmsg_poll msg;
484     int error;
485
486     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
487     if (port == NULL)
488         return(ENXIO);
489     msg.events = events;
490     msg.td = td;
491     error = lwkt_domsg(port, &msg.msg.msg);
492     if (error == 0)
493         return(msg.events);
494     return(seltrue(dev, msg.events, td));
495 }
496
497 int
498 dev_port_dkqfilter(lwkt_port_t port, dev_t dev, struct knote *kn)
499 {
500     struct cdevmsg_kqfilter msg;
501     int error;
502
503     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
504     if (port == NULL)
505         return(ENXIO);
506     msg.kn = kn;
507     error = lwkt_domsg(port, &msg.msg.msg);
508     if (error == 0)
509         return(msg.result);
510     return(ENODEV);
511 }
512
513 int
514 dev_port_dmmap(lwkt_port_t port, dev_t dev, vm_offset_t offset, int nprot)
515 {
516     struct cdevmsg_mmap msg;
517     int error;
518
519     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
520     if (port == NULL)
521         return(-1);
522     msg.offset = offset;
523     msg.nprot = nprot;
524     error = lwkt_domsg(port, &msg.msg.msg);
525     if (error == 0)
526         return(msg.result);
527     return(-1);
528 }
529
530 const char *
531 dev_dname(dev_t dev)
532 {
533     struct cdevsw *csw;
534
535     if ((csw = _devsw(dev)) != NULL)
536         return(csw->d_name);
537     return(NULL);
538 }
539
540 int
541 dev_dflags(dev_t dev)
542 {
543     struct cdevsw *csw;
544
545     if ((csw = _devsw(dev)) != NULL)
546         return(csw->d_flags);
547     return(0);
548 }
549
550 int
551 dev_dmaj(dev_t dev)
552 {
553     struct cdevsw *csw;
554
555     if ((csw = _devsw(dev)) != NULL)
556         return(csw->d_maj);
557     return(0);
558 }
559
560 lwkt_port_t
561 dev_dport(dev_t dev)
562 {
563     struct cdevsw *csw;
564
565     if ((csw = _devsw(dev)) != NULL) {
566         if (cdevport[major(dev)])       /* YYY too hackish */
567             return(cdevport[major(dev)]);
568         return(csw->d_port);
569     }
570     return(NULL);
571 }
572
573 #if 0
574 /*
575  * cdevsw[] array functions, moved from kern/kern_conf.c
576  */
577 struct cdevsw *
578 devsw(dev_t dev)
579 {
580     return(_devsw(dev));
581 }
582 #endif
583
584 /*
585  * Convert a cdevsw template into the real thing, filling in fields the
586  * device left empty with appropriate defaults.
587  */
588 void
589 compile_devsw(struct cdevsw *devsw)
590 {
591     static lwkt_port devsw_compat_port;
592
593     if (devsw_compat_port.mp_putport == NULL)
594         init_default_cdevsw_port(&devsw_compat_port);
595     
596     if (devsw->old_open == NULL)
597         devsw->old_open = noopen;
598     if (devsw->old_close == NULL)
599         devsw->old_close = noclose;
600     if (devsw->old_read == NULL)
601         devsw->old_read = noread;
602     if (devsw->old_write == NULL)
603         devsw->old_write = nowrite;
604     if (devsw->old_ioctl == NULL)
605         devsw->old_ioctl = noioctl;
606     if (devsw->old_poll == NULL)
607         devsw->old_poll = nopoll;
608     if (devsw->old_mmap == NULL)
609         devsw->old_mmap = nommap;
610     if (devsw->old_strategy == NULL)
611         devsw->old_strategy = nostrategy;
612     if (devsw->old_dump == NULL)
613         devsw->old_dump = nodump;
614     if (devsw->old_psize == NULL)
615         devsw->old_psize = nopsize;
616     if (devsw->old_kqfilter == NULL)
617         devsw->old_kqfilter = nokqfilter;
618
619     if (devsw->d_port == NULL)
620         devsw->d_port = &devsw_compat_port;
621 }
622
623 /*
624  * Add a cdevsw entry
625  */
626 int
627 cdevsw_add(struct cdevsw *newentry)
628 {
629     compile_devsw(newentry);
630     if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
631         printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
632             newentry->d_name, newentry->d_maj);
633         return (EINVAL);
634     }
635     if (cdevsw[newentry->d_maj]) {
636         printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
637             newentry->d_name, cdevsw[newentry->d_maj]->d_name);
638     }
639     cdevsw[newentry->d_maj] = newentry;
640     return (0);
641 }
642
643 /*
644  * Add a cdevsw entry and override the port.
645  */
646 lwkt_port_t
647 cdevsw_add_override(struct cdevsw *newentry, lwkt_port_t port)
648 {
649     int error;
650
651     if ((error = cdevsw_add(newentry)) == 0)
652         cdevport[newentry->d_maj] = port;
653     return(newentry->d_port);
654 }
655
656 lwkt_port_t
657 cdevsw_dev_override(dev_t dev, lwkt_port_t port)
658 {
659     struct cdevsw *csw;
660
661     KKASSERT(major(dev) >= 0 && major(dev) < NUMCDEVSW);
662     if ((csw = _devsw(dev)) != NULL) {
663         cdevport[major(dev)] = port;
664         return(csw->d_port);
665     }
666     return(NULL);
667 }
668
669 /*
670  *  Remove a cdevsw entry
671  */
672 int
673 cdevsw_remove(struct cdevsw *oldentry)
674 {
675     if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
676         printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
677             oldentry->d_name, oldentry->d_maj);
678         return EINVAL;
679     }
680     cdevsw[oldentry->d_maj] = NULL;
681     cdevport[oldentry->d_maj] = NULL;
682     return 0;
683 }
684