Date: Fri, 14 Mar 2003 17:34:28 -0500 (EST) From: Andrew Gallatin <gallatin@cs.duke.edu> To: Eric Anholt <eta@lclark.edu> Cc: freebsd-hackers@FreeBSD.ORG Subject: Re: per-open device private data, mmap Message-ID: <15986.22772.414400.413308@grasshopper.cs.duke.edu> In-Reply-To: <1047679748.622.30.camel@leguin> References: <1047679166.622.23.camel@leguin> <1047679748.622.30.camel@leguin>
next in thread | previous in thread | raw e-mail | index | archive | help
Eric Anholt writes:
> shouldn't be too big of an issue. The unique identifier is the big
> problem and the fileops trick should work for that.
>
> However, is this going to get easier some day? Are there any plans to
> pass the struct file down to the drivers and have a void * in there for
> private data?
>
I think that phk is working on this for 6.x
In the meantime, I have a new driver I"m developing which uses the
fileops trick you describe, but takes it a step further and conjurs up
a new vnode. That makes it work with mmap. I've not run into
any problems yet, but it is lightly tested.
Cheers,
Drew
/*
* Conjure up our own vnode out of thin air. We need the
* vnode so that we can stash a pointer to the per-connection
* priv struct for use in open/close/ioctl and mmap. This is
* tricky, because we need make it look enough like the device
* vnode so that VOP_GETATTR() works on the slave vnode in mmap()
*/
static int
xxx_conjur_vnode(dev_t dev, struct thread *td)
{
int error, fd;
struct filedesc *fdp;
struct file *fp;
struct vnode *vn = NULL, *vd = NULL;
struct cdev *rdev;
fdp = td->td_proc->p_fd;
if (fdp == NULL)
return (0);
if (td->td_dupfd >= 0)
return ENODEV;
rdev = xxx_malloc(sizeof(*rdev), M_WAITOK);
if ((error = falloc(td, &fp, &fd)) != 0)
goto abort_with_rdev;
vd = SLIST_FIRST(&dev->si_hlist);
if ((error = getnewvnode("none", vd->v_mount, vd->v_op, &vn)))
goto abort_with_falloc;
vn->v_type = VCHR;
/* XXXX really should clone v_vdata & not copy pointer */
vn->v_data = vd->v_data; /* for VTOI in devfs_getattr() */
/* copy our cdev info */
vn->v_rdev = rdev;
bcopy(vd->v_rdev, vn->v_rdev, sizeof(*rdev));
/* finally, save the data pointer (our softc) */
vn->v_rdev->si_drv2 = 0;
fp->f_data = (caddr_t)vn;
fp->f_flag = FREAD|FWRITE;
fp->f_ops = &xxx_fileops;
fp->f_type = DTYPE_VNODE; /* so that we can mmap */
/*
* Save the new fd as dupfd in the proc structure, then we have
* open() return the special error code (ENXIO). Returning with a
* dupfd and ENXIO causes magic things to happen in kern_open().
*/
td->td_dupfd = fd;
return 0;
abort_with_rdev:
xxx_free(rdev);
abort_with_falloc:
FILEDESC_LOCK(fdp);
fdp->fd_ofiles[fd] = NULL;
FILEDESC_UNLOCK(fdp);
fdrop(fp, td);
return (error);
}
static int
xxx_fileclose(struct file *fp, struct thread *td)
{
int ready_to_close;
struct vnode *vn;
struct cdev *rdev;
xxx_port_state_t *ps;
vn = (struct vnode *)fp->f_data;
rdev = vn->v_rdev;
ps = rdev->si_drv2;
rdev->si_drv2 = NULL;
/* replace the vnode ops so that devfs doesn't try to reclaim
anything */
vn->v_op = spec_vnodeop_p;
vn->v_type = VNON; /* don't want to freedev() in vgonel()*/
vgone(vn);
/* free our private rdev */
xxx_free(rdev);
if (ps) {
xxx_mutex_enter(&ps->sync);
/* Close the port if there are no more mappings */
ready_to_close = ps->ref_count == 0;
XXX_DEBUG_PRINT (XXX_DEBUG_OPENCLOSE,
("Board %d, port %d closed\n", ps->is->id, ps->port));
xxx_mutex_exit(&ps->sync);
if (ready_to_close) {
xxx_common_close (ps);
} else {
XXX_INFO (("Application closed file descriptor while "
"mappings still alive: port destruct delayed\n"));
}
}
return (0);
}
static int
xxx_mmap(dev_t dev, vm_offset_t offset,
#if MMAP_RETURNS_PINDEX == 0
vm_offset_t *paddr,
#endif
int nprot)
{
int status;
xxx_port_state_t *ps;
void *kva;
#if MMAP_RETURNS_PINDEX
vm_offset_t phys;
vm_offset_t *paddr = &phys;
#endif
ps = (xxx_port_state_t *)dev->si_drv2;
<...>
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?15986.22772.414400.413308>
