Skip site navigation (1)Skip section navigation (2)
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>