summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_conf.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-06-01 21:32:52 +0000
committerjhb <jhb@FreeBSD.org>2009-06-01 21:32:52 +0000
commitfea04a3fd158d65e9ffd20e50e38364d82b85c44 (patch)
tree3173f83adb95e5298ee26ee3bdedf7f6b4746d49 /sys/kern/kern_conf.c
parent904747c9f98f0e11c35daca161c7253a12c080f6 (diff)
downloadFreeBSD-src-fea04a3fd158d65e9ffd20e50e38364d82b85c44.zip
FreeBSD-src-fea04a3fd158d65e9ffd20e50e38364d82b85c44.tar.gz
Add an extension to the character device interface that allows character
device drivers to use arbitrary VM objects to satisfy individual mmap() requests. - A new d_mmap_single(cdev, &foff, objsize, &object, prot) callback is added to cdevsw. This function is called for each mmap() request. If it returns ENODEV, then the mmap() request will fall back to using the device's device pager object and d_mmap(). Otherwise, the method can return a VM object to satisfy this entire mmap() request via *object. It can also modify the starting offset into this object via *foff. This allows device drivers to use the file offset as a cookie to identify specific VM objects. - vm_mmap_vnode() has been changed to call vm_mmap_cdev() directly when mapping V_CHR vnodes. This avoids duplicating all the cdev mmap handling code and simplifies some of vm_mmap_vnode(). - D_VERSION has been bumped to D_VERSION_02. Older device drivers using D_VERSION_01 are still supported. MFC after: 1 month
Diffstat (limited to 'sys/kern/kern_conf.c')
-rw-r--r--sys/kern/kern_conf.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c
index 284f482..8a5577c 100644
--- a/sys/kern/kern_conf.c
+++ b/sys/kern/kern_conf.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <machine/stdarg.h>
#include <fs/devfs/devfs_int.h>
+#include <vm/vm.h>
static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
@@ -275,6 +276,7 @@ dead_strategy(struct bio *bp)
#define dead_dump (dumper_t *)enxio
#define dead_kqfilter (d_kqfilter_t *)enxio
+#define dead_mmap_single (d_mmap_single_t *)enodev
static struct cdevsw dead_cdevsw = {
.d_version = D_VERSION,
@@ -289,7 +291,8 @@ static struct cdevsw dead_cdevsw = {
.d_strategy = dead_strategy,
.d_name = "dead",
.d_dump = dead_dump,
- .d_kqfilter = dead_kqfilter
+ .d_kqfilter = dead_kqfilter,
+ .d_mmap_single = dead_mmap_single
};
/* Default methods if driver does not specify method */
@@ -301,6 +304,7 @@ static struct cdevsw dead_cdevsw = {
#define no_ioctl (d_ioctl_t *)enodev
#define no_mmap (d_mmap_t *)enodev
#define no_kqfilter (d_kqfilter_t *)enodev
+#define no_mmap_single (d_mmap_single_t *)enodev
static void
no_strategy(struct bio *bp)
@@ -480,6 +484,23 @@ giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
return (retval);
}
+static int
+giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
+ vm_object_t *object, int nprot)
+{
+ struct cdevsw *dsw;
+ int retval;
+
+ dsw = dev_refthread(dev);
+ if (dsw == NULL)
+ return (ENXIO);
+ mtx_lock(&Giant);
+ retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object,
+ nprot);
+ mtx_unlock(&Giant);
+ dev_relthread(dev);
+ return (retval);
+}
static void
notify(struct cdev *dev, const char *ev)
@@ -569,7 +590,8 @@ prep_cdevsw(struct cdevsw *devsw)
return;
}
- if (devsw->d_version != D_VERSION_01) {
+ if (devsw->d_version != D_VERSION_01 &&
+ devsw->d_version != D_VERSION_02) {
printf(
"WARNING: Device driver \"%s\" has wrong version %s\n",
devsw->d_name == NULL ? "???" : devsw->d_name,
@@ -585,6 +607,8 @@ prep_cdevsw(struct cdevsw *devsw)
devsw->d_dump = dead_dump;
devsw->d_kqfilter = dead_kqfilter;
}
+ if (devsw->d_version == D_VERSION_01)
+ devsw->d_mmap_single = NULL;
if (devsw->d_flags & D_NEEDGIANT) {
if (devsw->d_gianttrick == NULL) {
@@ -613,6 +637,7 @@ prep_cdevsw(struct cdevsw *devsw)
FIXUP(d_mmap, no_mmap, giant_mmap);
FIXUP(d_strategy, no_strategy, giant_strategy);
FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter);
+ FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single);
if (devsw->d_dump == NULL) devsw->d_dump = no_dump;
OpenPOWER on IntegriCloud