Merge branch 'vendor/OPENSSL'
[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  * Copyright (c) 1982, 1986, 1991, 1993
7  *      The Regents of the University of California.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/sysctl.h>
35 #include <sys/module.h>
36 #include <sys/malloc.h>
37 #include <sys/conf.h>
38 #include <sys/bio.h>
39 #include <sys/buf.h>
40 #include <sys/vnode.h>
41 #include <sys/queue.h>
42 #include <sys/device.h>
43 #include <sys/tree.h>
44 #include <sys/syslink_rpc.h>
45 #include <sys/proc.h>
46 #include <machine/stdarg.h>
47 #include <sys/devfs.h>
48 #include <sys/dsched.h>
49
50 #include <sys/thread2.h>
51 #include <sys/mplock2.h>
52
53 static int mpsafe_writes;
54 static int mplock_writes;
55 static int mpsafe_reads;
56 static int mplock_reads;
57 static int mpsafe_strategies;
58 static int mplock_strategies;
59
60 SYSCTL_INT(_kern, OID_AUTO, mpsafe_writes, CTLFLAG_RD, &mpsafe_writes,
61            0, "mpsafe writes");
62 SYSCTL_INT(_kern, OID_AUTO, mplock_writes, CTLFLAG_RD, &mplock_writes,
63            0, "non-mpsafe writes");
64 SYSCTL_INT(_kern, OID_AUTO, mpsafe_reads, CTLFLAG_RD, &mpsafe_reads,
65            0, "mpsafe reads");
66 SYSCTL_INT(_kern, OID_AUTO, mplock_reads, CTLFLAG_RD, &mplock_reads,
67            0, "non-mpsafe reads");
68 SYSCTL_INT(_kern, OID_AUTO, mpsafe_strategies, CTLFLAG_RD, &mpsafe_strategies,
69            0, "mpsafe strategies");
70 SYSCTL_INT(_kern, OID_AUTO, mplock_strategies, CTLFLAG_RD, &mplock_strategies,
71            0, "non-mpsafe strategies");
72
73 /*
74  * system link descriptors identify the command in the
75  * arguments structure.
76  */
77 #define DDESCNAME(name) __CONCAT(__CONCAT(dev_,name),_desc)
78
79 #define DEVOP_DESC_INIT(name)                                           \
80             struct syslink_desc DDESCNAME(name) = {                     \
81                 __offsetof(struct dev_ops, __CONCAT(d_, name)), \
82             #name }
83
84 DEVOP_DESC_INIT(default);
85 DEVOP_DESC_INIT(open);
86 DEVOP_DESC_INIT(close);
87 DEVOP_DESC_INIT(read);
88 DEVOP_DESC_INIT(write);
89 DEVOP_DESC_INIT(ioctl);
90 DEVOP_DESC_INIT(dump);
91 DEVOP_DESC_INIT(psize);
92 DEVOP_DESC_INIT(mmap);
93 DEVOP_DESC_INIT(mmap_single);
94 DEVOP_DESC_INIT(strategy);
95 DEVOP_DESC_INIT(kqfilter);
96 DEVOP_DESC_INIT(revoke);
97 DEVOP_DESC_INIT(clone);
98
99 /*
100  * Misc default ops
101  */
102 struct dev_ops dead_dev_ops;
103
104 static d_open_t         noopen;
105 static d_close_t        noclose;
106 static d_read_t         noread;
107 static d_write_t        nowrite;
108 static d_ioctl_t        noioctl;
109 static d_mmap_t         nommap;
110 static d_mmap_single_t  nommap_single;
111 static d_strategy_t     nostrategy;
112 static d_dump_t         nodump;
113 static d_psize_t        nopsize;
114 static d_kqfilter_t     nokqfilter;
115 static d_clone_t        noclone;
116 static d_revoke_t       norevoke;
117
118 struct dev_ops default_dev_ops = {
119         { "null" },
120         .d_default = NULL,      /* must be NULL */
121         .d_open = noopen,
122         .d_close = noclose,
123         .d_read = noread,
124         .d_write = nowrite,
125         .d_ioctl = noioctl,
126         .d_mmap = nommap,
127         .d_mmap_single = nommap_single,
128         .d_strategy = nostrategy,
129         .d_dump = nodump,
130         .d_psize = nopsize,
131         .d_kqfilter = nokqfilter,
132         .d_revoke = norevoke,
133         .d_clone = noclone
134 };
135
136 static __inline
137 int
138 dev_needmplock(cdev_t dev)
139 {
140     return((dev->si_ops->head.flags & D_MPSAFE) == 0);
141 }
142     
143 /************************************************************************
144  *                      GENERAL DEVICE API FUNCTIONS                    *
145  ************************************************************************
146  *
147  * The MPSAFEness of these depends on dev->si_ops->head.flags
148  */
149 int
150 dev_dopen(cdev_t dev, int oflags, int devtype, struct ucred *cred, struct file *fp)
151 {
152         struct dev_open_args ap;
153         int needmplock = dev_needmplock(dev);
154         int error;
155
156         ap.a_head.a_desc = &dev_open_desc;
157         ap.a_head.a_dev = dev;
158         ap.a_oflags = oflags;
159         ap.a_devtype = devtype;
160         ap.a_cred = cred;
161         ap.a_fp = fp;
162
163         if (needmplock)
164                 get_mplock();
165         error = dev->si_ops->d_open(&ap);
166         if (needmplock)
167                 rel_mplock();
168         return (error);
169 }
170
171 int
172 dev_dclose(cdev_t dev, int fflag, int devtype, struct file *fp)
173 {
174         struct dev_close_args ap;
175         int needmplock = dev_needmplock(dev);
176         int error;
177
178         ap.a_head.a_desc = &dev_close_desc;
179         ap.a_head.a_dev = dev;
180         ap.a_fflag = fflag;
181         ap.a_devtype = devtype;
182         ap.a_fp = fp;
183
184         if (needmplock)
185                 get_mplock();
186         error = dev->si_ops->d_close(&ap);
187         if (needmplock)
188                 rel_mplock();
189         return (error);
190 }
191
192 int
193 dev_dread(cdev_t dev, struct uio *uio, int ioflag, struct file *fp)
194 {
195         struct dev_read_args ap;
196         int needmplock = dev_needmplock(dev);
197         int error;
198
199         ap.a_head.a_desc = &dev_read_desc;
200         ap.a_head.a_dev = dev;
201         ap.a_uio = uio;
202         ap.a_ioflag = ioflag;
203         ap.a_fp = fp;
204
205         if (needmplock) {
206                 get_mplock();
207                 ++mplock_reads;
208         } else {
209                 ++mpsafe_reads;
210         }
211         error = dev->si_ops->d_read(&ap);
212         if (needmplock)
213                 rel_mplock();
214         if (error == 0)
215                 dev->si_lastread = time_uptime;
216         return (error);
217 }
218
219 int
220 dev_dwrite(cdev_t dev, struct uio *uio, int ioflag, struct file *fp)
221 {
222         struct dev_write_args ap;
223         int needmplock = dev_needmplock(dev);
224         int error;
225
226         dev->si_lastwrite = time_uptime;
227         ap.a_head.a_desc = &dev_write_desc;
228         ap.a_head.a_dev = dev;
229         ap.a_uio = uio;
230         ap.a_ioflag = ioflag;
231         ap.a_fp = fp;
232
233         if (needmplock) {
234                 get_mplock();
235                 ++mplock_writes;
236         } else {
237                 ++mpsafe_writes;
238         }
239         error = dev->si_ops->d_write(&ap);
240         if (needmplock)
241                 rel_mplock();
242         return (error);
243 }
244
245 int
246 dev_dioctl(cdev_t dev, u_long cmd, caddr_t data, int fflag, struct ucred *cred,
247            struct sysmsg *msg, struct file *fp)
248 {
249         struct dev_ioctl_args ap;
250         int needmplock = dev_needmplock(dev);
251         int error;
252
253         ap.a_head.a_desc = &dev_ioctl_desc;
254         ap.a_head.a_dev = dev;
255         ap.a_cmd = cmd;
256         ap.a_data = data;
257         ap.a_fflag = fflag;
258         ap.a_cred = cred;
259         ap.a_sysmsg = msg;
260         ap.a_fp = fp;
261
262         if (needmplock)
263                 get_mplock();
264         error = dev->si_ops->d_ioctl(&ap);
265         if (needmplock)
266                 rel_mplock();
267         return (error);
268 }
269
270 int
271 dev_dmmap(cdev_t dev, vm_offset_t offset, int nprot, struct file *fp)
272 {
273         struct dev_mmap_args ap;
274         int needmplock = dev_needmplock(dev);
275         int error;
276
277         ap.a_head.a_desc = &dev_mmap_desc;
278         ap.a_head.a_dev = dev;
279         ap.a_offset = offset;
280         ap.a_nprot = nprot;
281         ap.a_fp = fp;
282
283         if (needmplock)
284                 get_mplock();
285         error = dev->si_ops->d_mmap(&ap);
286         if (needmplock)
287                 rel_mplock();
288
289         if (error == 0)
290                 return(ap.a_result);
291         return(-1);
292 }
293
294 int
295 dev_dmmap_single(cdev_t dev, vm_ooffset_t *offset, vm_size_t size,
296                  struct vm_object **object, int nprot, struct file *fp)
297 {
298         struct dev_mmap_single_args ap;
299         int needmplock = dev_needmplock(dev);
300         int error;
301
302         ap.a_head.a_desc = &dev_mmap_single_desc;
303         ap.a_head.a_dev = dev;
304         ap.a_offset = offset;
305         ap.a_size = size;
306         ap.a_object = object;
307         ap.a_nprot = nprot;
308         ap.a_fp = fp;
309
310         if (needmplock)
311                 get_mplock();
312         error = dev->si_ops->d_mmap_single(&ap);
313         if (needmplock)
314                 rel_mplock();
315
316         return(error);
317 }
318
319 int
320 dev_dclone(cdev_t dev)
321 {
322         struct dev_clone_args ap;
323         int needmplock = dev_needmplock(dev);
324         int error;
325
326         ap.a_head.a_desc = &dev_clone_desc;
327         ap.a_head.a_dev = dev;
328
329         if (needmplock)
330                 get_mplock();
331         error = dev->si_ops->d_clone(&ap);
332         if (needmplock)
333                 rel_mplock();
334         return (error);
335 }
336
337 int
338 dev_drevoke(cdev_t dev)
339 {
340         struct dev_revoke_args ap;
341         int needmplock = dev_needmplock(dev);
342         int error;
343
344         ap.a_head.a_desc = &dev_revoke_desc;
345         ap.a_head.a_dev = dev;
346
347         if (needmplock)
348                 get_mplock();
349         error = dev->si_ops->d_revoke(&ap);
350         if (needmplock)
351                 rel_mplock();
352
353         return (error);
354 }
355
356 /*
357  * Core device strategy call, used to issue I/O on a device.  There are
358  * two versions, a non-chained version and a chained version.  The chained
359  * version reuses a BIO set up by vn_strategy().  The only difference is
360  * that, for now, we do not push a new tracking structure when chaining
361  * from vn_strategy.  XXX this will ultimately have to change.
362  */
363 void
364 dev_dstrategy(cdev_t dev, struct bio *bio)
365 {
366         struct dev_strategy_args ap;
367         struct bio_track *track;
368         int needmplock = dev_needmplock(dev);
369
370         ap.a_head.a_desc = &dev_strategy_desc;
371         ap.a_head.a_dev = dev;
372         ap.a_bio = bio;
373
374         KKASSERT(bio->bio_track == NULL);
375         KKASSERT(bio->bio_buf->b_cmd != BUF_CMD_DONE);
376         if (bio->bio_buf->b_cmd == BUF_CMD_READ)
377             track = &dev->si_track_read;
378         else
379             track = &dev->si_track_write;
380         bio_track_ref(track);
381         bio->bio_track = track;
382
383         if (dsched_is_clear_buf_priv(bio->bio_buf))
384                 dsched_new_buf(bio->bio_buf);
385
386         KKASSERT((bio->bio_flags & BIO_DONE) == 0);
387         if (needmplock) {
388                 get_mplock();
389                 ++mplock_strategies;
390         } else {
391                 ++mpsafe_strategies;
392         }
393         (void)dev->si_ops->d_strategy(&ap);
394         if (needmplock)
395                 rel_mplock();
396 }
397
398 void
399 dev_dstrategy_chain(cdev_t dev, struct bio *bio)
400 {
401         struct dev_strategy_args ap;
402         int needmplock = dev_needmplock(dev);
403
404         ap.a_head.a_desc = &dev_strategy_desc;
405         ap.a_head.a_dev = dev;
406         ap.a_bio = bio;
407
408         KKASSERT(bio->bio_track != NULL);
409         KKASSERT((bio->bio_flags & BIO_DONE) == 0);
410         if (needmplock)
411                 get_mplock();
412         (void)dev->si_ops->d_strategy(&ap);
413         if (needmplock)
414                 rel_mplock();
415 }
416
417 /*
418  * note: the disk layer is expected to set count, blkno, and secsize before
419  * forwarding the message.
420  */
421 int
422 dev_ddump(cdev_t dev, void *virtual, vm_offset_t physical, off_t offset,
423     size_t length)
424 {
425         struct dev_dump_args ap;
426         int needmplock = dev_needmplock(dev);
427         int error;
428
429         ap.a_head.a_desc = &dev_dump_desc;
430         ap.a_head.a_dev = dev;
431         ap.a_count = 0;
432         ap.a_blkno = 0;
433         ap.a_secsize = 0;
434         ap.a_virtual = virtual;
435         ap.a_physical = physical;
436         ap.a_offset = offset;
437         ap.a_length = length;
438
439         if (needmplock)
440                 get_mplock();
441         error = dev->si_ops->d_dump(&ap);
442         if (needmplock)
443                 rel_mplock();
444         return (error);
445 }
446
447 int64_t
448 dev_dpsize(cdev_t dev)
449 {
450         struct dev_psize_args ap;
451         int needmplock = dev_needmplock(dev);
452         int error;
453
454         ap.a_head.a_desc = &dev_psize_desc;
455         ap.a_head.a_dev = dev;
456
457         if (needmplock)
458                 get_mplock();
459         error = dev->si_ops->d_psize(&ap);
460         if (needmplock)
461                 rel_mplock();
462
463         if (error == 0)
464                 return (ap.a_result);
465         return(-1);
466 }
467
468 /*
469  * Pass-thru to the device kqfilter.
470  *
471  * NOTE: We explicitly preset a_result to 0 so d_kqfilter() functions
472  *       which return 0 do not have to bother setting a_result.
473  */
474 int
475 dev_dkqfilter(cdev_t dev, struct knote *kn, struct file *fp)
476 {
477         struct dev_kqfilter_args ap;
478         int needmplock = dev_needmplock(dev);
479         int error;
480
481         ap.a_head.a_desc = &dev_kqfilter_desc;
482         ap.a_head.a_dev = dev;
483         ap.a_kn = kn;
484         ap.a_result = 0;
485         ap.a_fp = fp;
486
487         if (needmplock)
488                 get_mplock();
489         error = dev->si_ops->d_kqfilter(&ap);
490         if (needmplock)
491                 rel_mplock();
492
493         if (error == 0) 
494                 return(ap.a_result);
495         return(ENODEV);
496 }
497
498 /************************************************************************
499  *                      DEVICE HELPER FUNCTIONS                         *
500  ************************************************************************/
501
502 /*
503  * MPSAFE
504  */
505 int
506 dev_drefs(cdev_t dev)
507 {
508     return(dev->si_sysref.refcnt);
509 }
510
511 /*
512  * MPSAFE
513  */
514 const char *
515 dev_dname(cdev_t dev)
516 {
517     return(dev->si_ops->head.name);
518 }
519
520 /*
521  * MPSAFE
522  */
523 int
524 dev_dflags(cdev_t dev)
525 {
526     return(dev->si_ops->head.flags);
527 }
528
529 /*
530  * MPSAFE
531  */
532 int
533 dev_dmaj(cdev_t dev)
534 {
535     return(dev->si_ops->head.maj);
536 }
537
538 /*
539  * Used when forwarding a request through layers.  The caller adjusts
540  * ap->a_head.a_dev and then calls this function.
541  */
542 int
543 dev_doperate(struct dev_generic_args *ap)
544 {
545     int (*func)(struct dev_generic_args *);
546     int needmplock = dev_needmplock(ap->a_dev);
547     int error;
548
549     func = *(void **)((char *)ap->a_dev->si_ops + ap->a_desc->sd_offset);
550
551     if (needmplock)
552             get_mplock();
553     error = func(ap);
554     if (needmplock)
555             rel_mplock();
556
557     return (error);
558 }
559
560 /*
561  * Used by the console intercept code only.  Issue an operation through
562  * a foreign ops structure allowing the ops structure associated
563  * with the device to remain intact.
564  */
565 int
566 dev_doperate_ops(struct dev_ops *ops, struct dev_generic_args *ap)
567 {
568     int (*func)(struct dev_generic_args *);
569     int needmplock = ((ops->head.flags & D_MPSAFE) == 0);
570     int error;
571
572     func = *(void **)((char *)ops + ap->a_desc->sd_offset);
573
574     if (needmplock)
575             get_mplock();
576     error = func(ap);
577     if (needmplock)
578             rel_mplock();
579
580     return (error);
581 }
582
583 /*
584  * Convert a template dev_ops into the real thing by filling in 
585  * uninitialized fields.
586  */
587 void
588 compile_dev_ops(struct dev_ops *ops)
589 {
590         int offset;
591
592         for (offset = offsetof(struct dev_ops, dev_ops_first_field);
593              offset <= offsetof(struct dev_ops, dev_ops_last_field);
594              offset += sizeof(void *)
595         ) {
596                 void **func_p = (void **)((char *)ops + offset);
597                 void **def_p = (void **)((char *)&default_dev_ops + offset);
598                 if (*func_p == NULL) {
599                         if (ops->d_default)
600                                 *func_p = ops->d_default;
601                         else
602                                 *func_p = *def_p;
603                 }
604         }
605 }
606
607 /************************************************************************
608  *                      MAJOR/MINOR SPACE FUNCTION                      *
609  ************************************************************************/
610
611 /*
612  * This makes a dev_ops entry visible to userland (e.g /dev/<blah>).
613  *
614  * Disk devices typically register their major, e.g. 'ad0', and then call
615  * into the disk label management code which overloads its own onto e.g. 'ad0'
616  * to support all the various slice and partition combinations.
617  *
618  * The mask/match supplied in this call are a full 32 bits and the same
619  * mask and match must be specified in a later dev_ops_remove() call to
620  * match this add.  However, the match value for the minor number should never
621  * have any bits set in the major number's bit range (8-15).  The mask value
622  * may be conveniently specified as -1 without creating any major number
623  * interference.
624  */
625
626 static
627 int
628 rb_dev_ops_compare(struct dev_ops_maj *a, struct dev_ops_maj *b)
629 {
630     if (a->maj < b->maj)
631         return(-1);
632     else if (a->maj > b->maj)
633         return(1);
634     return(0);
635 }
636
637 RB_GENERATE2(dev_ops_rb_tree, dev_ops_maj, rbnode, rb_dev_ops_compare, int, maj);
638
639 struct dev_ops_rb_tree dev_ops_rbhead = RB_INITIALIZER(dev_ops_rbhead);
640
641 int
642 dev_ops_remove_all(struct dev_ops *ops)
643 {
644         return devfs_destroy_dev_by_ops(ops, -1);
645 }
646
647 int
648 dev_ops_remove_minor(struct dev_ops *ops, int minor)
649 {
650         return devfs_destroy_dev_by_ops(ops, minor);
651 }
652
653 struct dev_ops *
654 dev_ops_intercept(cdev_t dev, struct dev_ops *iops)
655 {
656         struct dev_ops *oops = dev->si_ops;
657
658         compile_dev_ops(iops);
659         iops->head.maj = oops->head.maj;
660         iops->head.data = oops->head.data;
661         iops->head.flags = oops->head.flags;
662         dev->si_ops = iops;
663         dev->si_flags |= SI_INTERCEPTED;
664
665         return (oops);
666 }
667
668 void
669 dev_ops_restore(cdev_t dev, struct dev_ops *oops)
670 {
671         struct dev_ops *iops = dev->si_ops;
672
673         dev->si_ops = oops;
674         dev->si_flags &= ~SI_INTERCEPTED;
675         iops->head.maj = 0;
676         iops->head.data = NULL;
677         iops->head.flags = 0;
678 }
679
680 /************************************************************************
681  *                      DEFAULT DEV OPS FUNCTIONS                       *
682  ************************************************************************/
683
684
685 /*
686  * Unsupported devswitch functions (e.g. for writing to read-only device).
687  * XXX may belong elsewhere.
688  */
689 static int
690 norevoke(struct dev_revoke_args *ap)
691 {
692         /* take no action */
693         return(0);
694 }
695
696 static int
697 noclone(struct dev_clone_args *ap)
698 {
699         /* take no action */
700         return (0);     /* allow the clone */
701 }
702
703 static int
704 noopen(struct dev_open_args *ap)
705 {
706         return (ENODEV);
707 }
708
709 static int
710 noclose(struct dev_close_args *ap)
711 {
712         return (ENODEV);
713 }
714
715 static int
716 noread(struct dev_read_args *ap)
717 {
718         return (ENODEV);
719 }
720
721 static int
722 nowrite(struct dev_write_args *ap)
723 {
724         return (ENODEV);
725 }
726
727 static int
728 noioctl(struct dev_ioctl_args *ap)
729 {
730         return (ENODEV);
731 }
732
733 static int
734 nokqfilter(struct dev_kqfilter_args *ap)
735 {
736         return (ENODEV);
737 }
738
739 static int
740 nommap(struct dev_mmap_args *ap)
741 {
742         return (ENODEV);
743 }
744
745 static int
746 nommap_single(struct dev_mmap_single_args *ap)
747 {
748         return (ENODEV);
749 }
750
751 static int
752 nostrategy(struct dev_strategy_args *ap)
753 {
754         struct bio *bio = ap->a_bio;
755
756         bio->bio_buf->b_flags |= B_ERROR;
757         bio->bio_buf->b_error = EOPNOTSUPP;
758         biodone(bio);
759         return(0);
760 }
761
762 static int
763 nopsize(struct dev_psize_args *ap)
764 {
765         ap->a_result = 0;
766         return(0);
767 }
768
769 static int
770 nodump(struct dev_dump_args *ap)
771 {
772         return (ENODEV);
773 }
774
775 /*
776  * XXX this is probably bogus.  Any device that uses it isn't checking the
777  * minor number.
778  */
779 int
780 nullopen(struct dev_open_args *ap)
781 {
782         return (0);
783 }
784
785 int
786 nullclose(struct dev_close_args *ap)
787 {
788         return (0);
789 }
790