1/* $NetBSD: subr_devsw.c,v 1.34 2016/02/01 05:05:43 riz Exp $ */
2
3/*-
4 * Copyright (c) 2001, 2002, 2007, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by MAEKAWA Masahide <gehenna@NetBSD.org>, and by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Overview
34 *
35 * subr_devsw.c: registers device drivers by name and by major
36 * number, and provides wrapper methods for performing I/O and
37 * other tasks on device drivers, keying on the device number
38 * (dev_t).
39 *
40 * When the system is built, the config(8) command generates
41 * static tables of device drivers built into the kernel image
42 * along with their associated methods. These are recorded in
43 * the cdevsw0 and bdevsw0 tables. Drivers can also be added to
44 * and removed from the system dynamically.
45 *
46 * Allocation
47 *
48 * When the system initially boots only the statically allocated
49 * indexes (bdevsw0, cdevsw0) are used. If these overflow due to
50 * allocation, we allocate a fixed block of memory to hold the new,
51 * expanded index. This "fork" of the table is only ever performed
52 * once in order to guarantee that other threads may safely access
53 * the device tables:
54 *
55 * o Once a thread has a "reference" to the table via an earlier
56 * open() call, we know that the entry in the table must exist
57 * and so it is safe to access it.
58 *
59 * o Regardless of whether other threads see the old or new
60 * pointers, they will point to a correct device switch
61 * structure for the operation being performed.
62 *
63 * XXX Currently, the wrapper methods such as cdev_read() verify
64 * that a device driver does in fact exist before calling the
65 * associated driver method. This should be changed so that
66 * once the device is has been referenced by a vnode (opened),
67 * calling the other methods should be valid until that reference
68 * is dropped.
69 */
70
71#include <sys/cdefs.h>
72__KERNEL_RCSID(0, "$NetBSD: subr_devsw.c,v 1.34 2016/02/01 05:05:43 riz Exp $");
73
74#ifdef _KERNEL_OPT
75#include "opt_dtrace.h"
76#endif
77
78#include <sys/param.h>
79#include <sys/conf.h>
80#include <sys/kmem.h>
81#include <sys/systm.h>
82#include <sys/poll.h>
83#include <sys/tty.h>
84#include <sys/cpu.h>
85#include <sys/buf.h>
86#include <sys/reboot.h>
87#include <sys/sdt.h>
88
89#ifdef DEVSW_DEBUG
90#define DPRINTF(x) printf x
91#else /* DEVSW_DEBUG */
92#define DPRINTF(x)
93#endif /* DEVSW_DEBUG */
94
95#define MAXDEVSW 512 /* the maximum of major device number */
96#define BDEVSW_SIZE (sizeof(struct bdevsw *))
97#define CDEVSW_SIZE (sizeof(struct cdevsw *))
98#define DEVSWCONV_SIZE (sizeof(struct devsw_conv))
99
100extern const struct bdevsw **bdevsw, *bdevsw0[];
101extern const struct cdevsw **cdevsw, *cdevsw0[];
102extern struct devsw_conv *devsw_conv, devsw_conv0[];
103extern const int sys_bdevsws, sys_cdevsws;
104extern int max_bdevsws, max_cdevsws, max_devsw_convs;
105
106static int bdevsw_attach(const struct bdevsw *, devmajor_t *);
107static int cdevsw_attach(const struct cdevsw *, devmajor_t *);
108static void devsw_detach_locked(const struct bdevsw *, const struct cdevsw *);
109
110kmutex_t device_lock;
111
112void (*biodone_vfs)(buf_t *) = (void *)nullop;
113
114void
115devsw_init(void)
116{
117
118 KASSERT(sys_bdevsws < MAXDEVSW - 1);
119 KASSERT(sys_cdevsws < MAXDEVSW - 1);
120 mutex_init(&device_lock, MUTEX_DEFAULT, IPL_NONE);
121}
122
123int
124devsw_attach(const char *devname,
125 const struct bdevsw *bdev, devmajor_t *bmajor,
126 const struct cdevsw *cdev, devmajor_t *cmajor)
127{
128 struct devsw_conv *conv;
129 char *name;
130 int error, i;
131 size_t len;
132
133 if (devname == NULL || cdev == NULL)
134 return (EINVAL);
135
136 mutex_enter(&device_lock);
137
138 for (i = 0 ; i < max_devsw_convs ; i++) {
139 conv = &devsw_conv[i];
140 if (conv->d_name == NULL || strcmp(devname, conv->d_name) != 0)
141 continue;
142
143 if (*bmajor < 0)
144 *bmajor = conv->d_bmajor;
145 if (*cmajor < 0)
146 *cmajor = conv->d_cmajor;
147
148 if (*bmajor != conv->d_bmajor || *cmajor != conv->d_cmajor) {
149 error = EINVAL;
150 goto fail;
151 }
152 if ((*bmajor >= 0 && bdev == NULL) || *cmajor < 0) {
153 error = EINVAL;
154 goto fail;
155 }
156
157 if ((*bmajor >= 0 && bdevsw[*bmajor] != NULL) ||
158 cdevsw[*cmajor] != NULL) {
159 error = EEXIST;
160 goto fail;
161 }
162
163 if (bdev != NULL)
164 bdevsw[*bmajor] = bdev;
165 cdevsw[*cmajor] = cdev;
166
167 mutex_exit(&device_lock);
168 return (0);
169 }
170
171 error = bdevsw_attach(bdev, bmajor);
172 if (error != 0)
173 goto fail;
174 error = cdevsw_attach(cdev, cmajor);
175 if (error != 0) {
176 devsw_detach_locked(bdev, NULL);
177 goto fail;
178 }
179
180 for (i = 0 ; i < max_devsw_convs ; i++) {
181 if (devsw_conv[i].d_name == NULL)
182 break;
183 }
184 if (i == max_devsw_convs) {
185 struct devsw_conv *newptr;
186 int old_convs, new_convs;
187
188 old_convs = max_devsw_convs;
189 new_convs = old_convs + 1;
190
191 newptr = kmem_zalloc(new_convs * DEVSWCONV_SIZE, KM_NOSLEEP);
192 if (newptr == NULL) {
193 devsw_detach_locked(bdev, cdev);
194 error = ENOMEM;
195 goto fail;
196 }
197 newptr[old_convs].d_name = NULL;
198 newptr[old_convs].d_bmajor = -1;
199 newptr[old_convs].d_cmajor = -1;
200 memcpy(newptr, devsw_conv, old_convs * DEVSWCONV_SIZE);
201 if (devsw_conv != devsw_conv0)
202 kmem_free(devsw_conv, old_convs * DEVSWCONV_SIZE);
203 devsw_conv = newptr;
204 max_devsw_convs = new_convs;
205 }
206
207 len = strlen(devname) + 1;
208 name = kmem_alloc(len, KM_NOSLEEP);
209 if (name == NULL) {
210 devsw_detach_locked(bdev, cdev);
211 error = ENOMEM;
212 goto fail;
213 }
214 strlcpy(name, devname, len);
215
216 devsw_conv[i].d_name = name;
217 devsw_conv[i].d_bmajor = *bmajor;
218 devsw_conv[i].d_cmajor = *cmajor;
219
220 mutex_exit(&device_lock);
221 return (0);
222 fail:
223 mutex_exit(&device_lock);
224 return (error);
225}
226
227static int
228bdevsw_attach(const struct bdevsw *devsw, devmajor_t *devmajor)
229{
230 const struct bdevsw **newptr;
231 devmajor_t bmajor;
232 int i;
233
234 KASSERT(mutex_owned(&device_lock));
235
236 if (devsw == NULL)
237 return (0);
238
239 if (*devmajor < 0) {
240 for (bmajor = sys_bdevsws ; bmajor < max_bdevsws ; bmajor++) {
241 if (bdevsw[bmajor] != NULL)
242 continue;
243 for (i = 0 ; i < max_devsw_convs ; i++) {
244 if (devsw_conv[i].d_bmajor == bmajor)
245 break;
246 }
247 if (i != max_devsw_convs)
248 continue;
249 break;
250 }
251 *devmajor = bmajor;
252 }
253
254 if (*devmajor >= MAXDEVSW) {
255 printf("bdevsw_attach: block majors exhausted");
256 return (ENOMEM);
257 }
258
259 if (*devmajor >= max_bdevsws) {
260 KASSERT(bdevsw == bdevsw0);
261 newptr = kmem_zalloc(MAXDEVSW * BDEVSW_SIZE, KM_NOSLEEP);
262 if (newptr == NULL)
263 return (ENOMEM);
264 memcpy(newptr, bdevsw, max_bdevsws * BDEVSW_SIZE);
265 bdevsw = newptr;
266 max_bdevsws = MAXDEVSW;
267 }
268
269 if (bdevsw[*devmajor] != NULL)
270 return (EEXIST);
271
272 bdevsw[*devmajor] = devsw;
273
274 return (0);
275}
276
277static int
278cdevsw_attach(const struct cdevsw *devsw, devmajor_t *devmajor)
279{
280 const struct cdevsw **newptr;
281 devmajor_t cmajor;
282 int i;
283
284 KASSERT(mutex_owned(&device_lock));
285
286 if (*devmajor < 0) {
287 for (cmajor = sys_cdevsws ; cmajor < max_cdevsws ; cmajor++) {
288 if (cdevsw[cmajor] != NULL)
289 continue;
290 for (i = 0 ; i < max_devsw_convs ; i++) {
291 if (devsw_conv[i].d_cmajor == cmajor)
292 break;
293 }
294 if (i != max_devsw_convs)
295 continue;
296 break;
297 }
298 *devmajor = cmajor;
299 }
300
301 if (*devmajor >= MAXDEVSW) {
302 printf("cdevsw_attach: character majors exhausted");
303 return (ENOMEM);
304 }
305
306 if (*devmajor >= max_cdevsws) {
307 KASSERT(cdevsw == cdevsw0);
308 newptr = kmem_zalloc(MAXDEVSW * CDEVSW_SIZE, KM_NOSLEEP);
309 if (newptr == NULL)
310 return (ENOMEM);
311 memcpy(newptr, cdevsw, max_cdevsws * CDEVSW_SIZE);
312 cdevsw = newptr;
313 max_cdevsws = MAXDEVSW;
314 }
315
316 if (cdevsw[*devmajor] != NULL)
317 return (EEXIST);
318
319 cdevsw[*devmajor] = devsw;
320
321 return (0);
322}
323
324static void
325devsw_detach_locked(const struct bdevsw *bdev, const struct cdevsw *cdev)
326{
327 int i;
328
329 KASSERT(mutex_owned(&device_lock));
330
331 if (bdev != NULL) {
332 for (i = 0 ; i < max_bdevsws ; i++) {
333 if (bdevsw[i] != bdev)
334 continue;
335 bdevsw[i] = NULL;
336 break;
337 }
338 }
339 if (cdev != NULL) {
340 for (i = 0 ; i < max_cdevsws ; i++) {
341 if (cdevsw[i] != cdev)
342 continue;
343 cdevsw[i] = NULL;
344 break;
345 }
346 }
347}
348
349int
350devsw_detach(const struct bdevsw *bdev, const struct cdevsw *cdev)
351{
352
353 mutex_enter(&device_lock);
354 devsw_detach_locked(bdev, cdev);
355 mutex_exit(&device_lock);
356 return 0;
357}
358
359/*
360 * Look up a block device by number.
361 *
362 * => Caller must ensure that the device is attached.
363 */
364const struct bdevsw *
365bdevsw_lookup(dev_t dev)
366{
367 devmajor_t bmajor;
368
369 if (dev == NODEV)
370 return (NULL);
371 bmajor = major(dev);
372 if (bmajor < 0 || bmajor >= max_bdevsws)
373 return (NULL);
374
375 return (bdevsw[bmajor]);
376}
377
378/*
379 * Look up a character device by number.
380 *
381 * => Caller must ensure that the device is attached.
382 */
383const struct cdevsw *
384cdevsw_lookup(dev_t dev)
385{
386 devmajor_t cmajor;
387
388 if (dev == NODEV)
389 return (NULL);
390 cmajor = major(dev);
391 if (cmajor < 0 || cmajor >= max_cdevsws)
392 return (NULL);
393
394 return (cdevsw[cmajor]);
395}
396
397/*
398 * Look up a block device by reference to its operations set.
399 *
400 * => Caller must ensure that the device is not detached, and therefore
401 * that the returned major is still valid when dereferenced.
402 */
403devmajor_t
404bdevsw_lookup_major(const struct bdevsw *bdev)
405{
406 devmajor_t bmajor;
407
408 for (bmajor = 0 ; bmajor < max_bdevsws ; bmajor++) {
409 if (bdevsw[bmajor] == bdev)
410 return (bmajor);
411 }
412
413 return (NODEVMAJOR);
414}
415
416/*
417 * Look up a character device by reference to its operations set.
418 *
419 * => Caller must ensure that the device is not detached, and therefore
420 * that the returned major is still valid when dereferenced.
421 */
422devmajor_t
423cdevsw_lookup_major(const struct cdevsw *cdev)
424{
425 devmajor_t cmajor;
426
427 for (cmajor = 0 ; cmajor < max_cdevsws ; cmajor++) {
428 if (cdevsw[cmajor] == cdev)
429 return (cmajor);
430 }
431
432 return (NODEVMAJOR);
433}
434
435/*
436 * Convert from block major number to name.
437 *
438 * => Caller must ensure that the device is not detached, and therefore
439 * that the name pointer is still valid when dereferenced.
440 */
441const char *
442devsw_blk2name(devmajor_t bmajor)
443{
444 const char *name;
445 devmajor_t cmajor;
446 int i;
447
448 name = NULL;
449 cmajor = -1;
450
451 mutex_enter(&device_lock);
452 if (bmajor < 0 || bmajor >= max_bdevsws || bdevsw[bmajor] == NULL) {
453 mutex_exit(&device_lock);
454 return (NULL);
455 }
456 for (i = 0 ; i < max_devsw_convs; i++) {
457 if (devsw_conv[i].d_bmajor == bmajor) {
458 cmajor = devsw_conv[i].d_cmajor;
459 break;
460 }
461 }
462 if (cmajor >= 0 && cmajor < max_cdevsws && cdevsw[cmajor] != NULL)
463 name = devsw_conv[i].d_name;
464 mutex_exit(&device_lock);
465
466 return (name);
467}
468
469/*
470 * Convert char major number to device driver name.
471 */
472const char *
473cdevsw_getname(devmajor_t major)
474{
475 const char *name;
476 int i;
477
478 name = NULL;
479
480 if (major < 0)
481 return (NULL);
482
483 mutex_enter(&device_lock);
484 for (i = 0 ; i < max_devsw_convs; i++) {
485 if (devsw_conv[i].d_cmajor == major) {
486 name = devsw_conv[i].d_name;
487 break;
488 }
489 }
490 mutex_exit(&device_lock);
491 return (name);
492}
493
494/*
495 * Convert block major number to device driver name.
496 */
497const char *
498bdevsw_getname(devmajor_t major)
499{
500 const char *name;
501 int i;
502
503 name = NULL;
504
505 if (major < 0)
506 return (NULL);
507
508 mutex_enter(&device_lock);
509 for (i = 0 ; i < max_devsw_convs; i++) {
510 if (devsw_conv[i].d_bmajor == major) {
511 name = devsw_conv[i].d_name;
512 break;
513 }
514 }
515 mutex_exit(&device_lock);
516 return (name);
517}
518
519/*
520 * Convert from device name to block major number.
521 *
522 * => Caller must ensure that the device is not detached, and therefore
523 * that the major number is still valid when dereferenced.
524 */
525devmajor_t
526devsw_name2blk(const char *name, char *devname, size_t devnamelen)
527{
528 struct devsw_conv *conv;
529 devmajor_t bmajor;
530 int i;
531
532 if (name == NULL)
533 return (NODEVMAJOR);
534
535 mutex_enter(&device_lock);
536 for (i = 0 ; i < max_devsw_convs ; i++) {
537 size_t len;
538
539 conv = &devsw_conv[i];
540 if (conv->d_name == NULL)
541 continue;
542 len = strlen(conv->d_name);
543 if (strncmp(conv->d_name, name, len) != 0)
544 continue;
545 if (*(name +len) && !isdigit(*(name + len)))
546 continue;
547 bmajor = conv->d_bmajor;
548 if (bmajor < 0 || bmajor >= max_bdevsws ||
549 bdevsw[bmajor] == NULL)
550 break;
551 if (devname != NULL) {
552#ifdef DEVSW_DEBUG
553 if (strlen(conv->d_name) >= devnamelen)
554 printf("devsw_name2blk: too short buffer");
555#endif /* DEVSW_DEBUG */
556 strncpy(devname, conv->d_name, devnamelen);
557 devname[devnamelen - 1] = '\0';
558 }
559 mutex_exit(&device_lock);
560 return (bmajor);
561 }
562
563 mutex_exit(&device_lock);
564 return (NODEVMAJOR);
565}
566
567/*
568 * Convert from device name to char major number.
569 *
570 * => Caller must ensure that the device is not detached, and therefore
571 * that the major number is still valid when dereferenced.
572 */
573devmajor_t
574devsw_name2chr(const char *name, char *devname, size_t devnamelen)
575{
576 struct devsw_conv *conv;
577 devmajor_t cmajor;
578 int i;
579
580 if (name == NULL)
581 return (NODEVMAJOR);
582
583 mutex_enter(&device_lock);
584 for (i = 0 ; i < max_devsw_convs ; i++) {
585 size_t len;
586
587 conv = &devsw_conv[i];
588 if (conv->d_name == NULL)
589 continue;
590 len = strlen(conv->d_name);
591 if (strncmp(conv->d_name, name, len) != 0)
592 continue;
593 if (*(name +len) && !isdigit(*(name + len)))
594 continue;
595 cmajor = conv->d_cmajor;
596 if (cmajor < 0 || cmajor >= max_cdevsws ||
597 cdevsw[cmajor] == NULL)
598 break;
599 if (devname != NULL) {
600#ifdef DEVSW_DEBUG
601 if (strlen(conv->d_name) >= devnamelen)
602 printf("devsw_name2chr: too short buffer");
603#endif /* DEVSW_DEBUG */
604 strncpy(devname, conv->d_name, devnamelen);
605 devname[devnamelen - 1] = '\0';
606 }
607 mutex_exit(&device_lock);
608 return (cmajor);
609 }
610
611 mutex_exit(&device_lock);
612 return (NODEVMAJOR);
613}
614
615/*
616 * Convert from character dev_t to block dev_t.
617 *
618 * => Caller must ensure that the device is not detached, and therefore
619 * that the major number is still valid when dereferenced.
620 */
621dev_t
622devsw_chr2blk(dev_t cdev)
623{
624 devmajor_t bmajor, cmajor;
625 int i;
626 dev_t rv;
627
628 cmajor = major(cdev);
629 bmajor = NODEVMAJOR;
630 rv = NODEV;
631
632 mutex_enter(&device_lock);
633 if (cmajor < 0 || cmajor >= max_cdevsws || cdevsw[cmajor] == NULL) {
634 mutex_exit(&device_lock);
635 return (NODEV);
636 }
637 for (i = 0 ; i < max_devsw_convs ; i++) {
638 if (devsw_conv[i].d_cmajor == cmajor) {
639 bmajor = devsw_conv[i].d_bmajor;
640 break;
641 }
642 }
643 if (bmajor >= 0 && bmajor < max_bdevsws && bdevsw[bmajor] != NULL)
644 rv = makedev(bmajor, minor(cdev));
645 mutex_exit(&device_lock);
646
647 return (rv);
648}
649
650/*
651 * Convert from block dev_t to character dev_t.
652 *
653 * => Caller must ensure that the device is not detached, and therefore
654 * that the major number is still valid when dereferenced.
655 */
656dev_t
657devsw_blk2chr(dev_t bdev)
658{
659 devmajor_t bmajor, cmajor;
660 int i;
661 dev_t rv;
662
663 bmajor = major(bdev);
664 cmajor = NODEVMAJOR;
665 rv = NODEV;
666
667 mutex_enter(&device_lock);
668 if (bmajor < 0 || bmajor >= max_bdevsws || bdevsw[bmajor] == NULL) {
669 mutex_exit(&device_lock);
670 return (NODEV);
671 }
672 for (i = 0 ; i < max_devsw_convs ; i++) {
673 if (devsw_conv[i].d_bmajor == bmajor) {
674 cmajor = devsw_conv[i].d_cmajor;
675 break;
676 }
677 }
678 if (cmajor >= 0 && cmajor < max_cdevsws && cdevsw[cmajor] != NULL)
679 rv = makedev(cmajor, minor(bdev));
680 mutex_exit(&device_lock);
681
682 return (rv);
683}
684
685/*
686 * Device access methods.
687 */
688
689#define DEV_LOCK(d) \
690 if ((mpflag = (d->d_flag & D_MPSAFE)) == 0) { \
691 KERNEL_LOCK(1, NULL); \
692 }
693
694#define DEV_UNLOCK(d) \
695 if (mpflag == 0) { \
696 KERNEL_UNLOCK_ONE(NULL); \
697 }
698
699int
700bdev_open(dev_t dev, int flag, int devtype, lwp_t *l)
701{
702 const struct bdevsw *d;
703 int rv, mpflag;
704
705 /*
706 * For open we need to lock, in order to synchronize
707 * with attach/detach.
708 */
709 mutex_enter(&device_lock);
710 d = bdevsw_lookup(dev);
711 mutex_exit(&device_lock);
712 if (d == NULL)
713 return ENXIO;
714
715 DEV_LOCK(d);
716 rv = (*d->d_open)(dev, flag, devtype, l);
717 DEV_UNLOCK(d);
718
719 return rv;
720}
721
722int
723bdev_close(dev_t dev, int flag, int devtype, lwp_t *l)
724{
725 const struct bdevsw *d;
726 int rv, mpflag;
727
728 if ((d = bdevsw_lookup(dev)) == NULL)
729 return ENXIO;
730
731 DEV_LOCK(d);
732 rv = (*d->d_close)(dev, flag, devtype, l);
733 DEV_UNLOCK(d);
734
735 return rv;
736}
737
738SDT_PROVIDER_DECLARE(io);
739SDT_PROBE_DEFINE1(io, kernel, , start, "struct buf *"/*bp*/);
740
741void
742bdev_strategy(struct buf *bp)
743{
744 const struct bdevsw *d;
745 int mpflag;
746
747 SDT_PROBE1(io, kernel, , start, bp);
748
749 if ((d = bdevsw_lookup(bp->b_dev)) == NULL) {
750 bp->b_error = ENXIO;
751 bp->b_resid = bp->b_bcount;
752 biodone_vfs(bp); /* biodone() iff vfs present */
753 return;
754 }
755
756 DEV_LOCK(d);
757 (*d->d_strategy)(bp);
758 DEV_UNLOCK(d);
759}
760
761int
762bdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
763{
764 const struct bdevsw *d;
765 int rv, mpflag;
766
767 if ((d = bdevsw_lookup(dev)) == NULL)
768 return ENXIO;
769
770 DEV_LOCK(d);
771 rv = (*d->d_ioctl)(dev, cmd, data, flag, l);
772 DEV_UNLOCK(d);
773
774 return rv;
775}
776
777int
778bdev_dump(dev_t dev, daddr_t addr, void *data, size_t sz)
779{
780 const struct bdevsw *d;
781 int rv;
782
783 /*
784 * Dump can be called without the device open. Since it can
785 * currently only be called with the system paused (and in a
786 * potentially unstable state), we don't perform any locking.
787 */
788 if ((d = bdevsw_lookup(dev)) == NULL)
789 return ENXIO;
790
791 /* DEV_LOCK(d); */
792 rv = (*d->d_dump)(dev, addr, data, sz);
793 /* DEV_UNLOCK(d); */
794
795 return rv;
796}
797
798int
799bdev_type(dev_t dev)
800{
801 const struct bdevsw *d;
802
803 if ((d = bdevsw_lookup(dev)) == NULL)
804 return D_OTHER;
805 return d->d_flag & D_TYPEMASK;
806}
807
808int
809bdev_size(dev_t dev)
810{
811 const struct bdevsw *d;
812 int rv, mpflag = 0;
813
814 if ((d = bdevsw_lookup(dev)) == NULL ||
815 d->d_psize == NULL)
816 return -1;
817
818 /*
819 * Don't to try lock the device if we're dumping.
820 * XXX: is there a better way to test this?
821 */
822 if ((boothowto & RB_DUMP) == 0)
823 DEV_LOCK(d);
824 rv = (*d->d_psize)(dev);
825 if ((boothowto & RB_DUMP) == 0)
826 DEV_UNLOCK(d);
827
828 return rv;
829}
830
831int
832bdev_discard(dev_t dev, off_t pos, off_t len)
833{
834 const struct bdevsw *d;
835 int rv, mpflag;
836
837 if ((d = bdevsw_lookup(dev)) == NULL)
838 return ENXIO;
839
840 DEV_LOCK(d);
841 rv = (*d->d_discard)(dev, pos, len);
842 DEV_UNLOCK(d);
843
844 return rv;
845}
846
847int
848cdev_open(dev_t dev, int flag, int devtype, lwp_t *l)
849{
850 const struct cdevsw *d;
851 int rv, mpflag;
852
853 /*
854 * For open we need to lock, in order to synchronize
855 * with attach/detach.
856 */
857 mutex_enter(&device_lock);
858 d = cdevsw_lookup(dev);
859 mutex_exit(&device_lock);
860 if (d == NULL)
861 return ENXIO;
862
863 DEV_LOCK(d);
864 rv = (*d->d_open)(dev, flag, devtype, l);
865 DEV_UNLOCK(d);
866
867 return rv;
868}
869
870int
871cdev_close(dev_t dev, int flag, int devtype, lwp_t *l)
872{
873 const struct cdevsw *d;
874 int rv, mpflag;
875
876 if ((d = cdevsw_lookup(dev)) == NULL)
877 return ENXIO;
878
879 DEV_LOCK(d);
880 rv = (*d->d_close)(dev, flag, devtype, l);
881 DEV_UNLOCK(d);
882
883 return rv;
884}
885
886int
887cdev_read(dev_t dev, struct uio *uio, int flag)
888{
889 const struct cdevsw *d;
890 int rv, mpflag;
891
892 if ((d = cdevsw_lookup(dev)) == NULL)
893 return ENXIO;
894
895 DEV_LOCK(d);
896 rv = (*d->d_read)(dev, uio, flag);
897 DEV_UNLOCK(d);
898
899 return rv;
900}
901
902int
903cdev_write(dev_t dev, struct uio *uio, int flag)
904{
905 const struct cdevsw *d;
906 int rv, mpflag;
907
908 if ((d = cdevsw_lookup(dev)) == NULL)
909 return ENXIO;
910
911 DEV_LOCK(d);
912 rv = (*d->d_write)(dev, uio, flag);
913 DEV_UNLOCK(d);
914
915 return rv;
916}
917
918int
919cdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
920{
921 const struct cdevsw *d;
922 int rv, mpflag;
923
924 if ((d = cdevsw_lookup(dev)) == NULL)
925 return ENXIO;
926
927 DEV_LOCK(d);
928 rv = (*d->d_ioctl)(dev, cmd, data, flag, l);
929 DEV_UNLOCK(d);
930
931 return rv;
932}
933
934void
935cdev_stop(struct tty *tp, int flag)
936{
937 const struct cdevsw *d;
938 int mpflag;
939
940 if ((d = cdevsw_lookup(tp->t_dev)) == NULL)
941 return;
942
943 DEV_LOCK(d);
944 (*d->d_stop)(tp, flag);
945 DEV_UNLOCK(d);
946}
947
948struct tty *
949cdev_tty(dev_t dev)
950{
951 const struct cdevsw *d;
952
953 if ((d = cdevsw_lookup(dev)) == NULL)
954 return NULL;
955
956 /* XXX Check if necessary. */
957 if (d->d_tty == NULL)
958 return NULL;
959
960 return (*d->d_tty)(dev);
961}
962
963int
964cdev_poll(dev_t dev, int flag, lwp_t *l)
965{
966 const struct cdevsw *d;
967 int rv, mpflag;
968
969 if ((d = cdevsw_lookup(dev)) == NULL)
970 return POLLERR;
971
972 DEV_LOCK(d);
973 rv = (*d->d_poll)(dev, flag, l);
974 DEV_UNLOCK(d);
975
976 return rv;
977}
978
979paddr_t
980cdev_mmap(dev_t dev, off_t off, int flag)
981{
982 const struct cdevsw *d;
983 paddr_t rv;
984 int mpflag;
985
986 if ((d = cdevsw_lookup(dev)) == NULL)
987 return (paddr_t)-1LL;
988
989 DEV_LOCK(d);
990 rv = (*d->d_mmap)(dev, off, flag);
991 DEV_UNLOCK(d);
992
993 return rv;
994}
995
996int
997cdev_kqfilter(dev_t dev, struct knote *kn)
998{
999 const struct cdevsw *d;
1000 int rv, mpflag;
1001
1002 if ((d = cdevsw_lookup(dev)) == NULL)
1003 return ENXIO;
1004
1005 DEV_LOCK(d);
1006 rv = (*d->d_kqfilter)(dev, kn);
1007 DEV_UNLOCK(d);
1008
1009 return rv;
1010}
1011
1012int
1013cdev_discard(dev_t dev, off_t pos, off_t len)
1014{
1015 const struct cdevsw *d;
1016 int rv, mpflag;
1017
1018 if ((d = cdevsw_lookup(dev)) == NULL)
1019 return ENXIO;
1020
1021 DEV_LOCK(d);
1022 rv = (*d->d_discard)(dev, pos, len);
1023 DEV_UNLOCK(d);
1024
1025 return rv;
1026}
1027
1028int
1029cdev_type(dev_t dev)
1030{
1031 const struct cdevsw *d;
1032
1033 if ((d = cdevsw_lookup(dev)) == NULL)
1034 return D_OTHER;
1035 return d->d_flag & D_TYPEMASK;
1036}
1037