Diff for /src/sys/kern/kern_device.c between versions 1.10 and 1.11

version 1.10, 2004/05/13 23:49:23 version 1.11, 2004/05/19 22:52:58
Line 43 Line 43
 #include <sys/thread2.h>  #include <sys/thread2.h>
 #include <sys/msgport2.h>  #include <sys/msgport2.h>
   
 static struct cdevsw    *cdevsw[NUMCDEVSW];  static struct cdevlink  *cdevbase[NUMCDEVSW];
 static struct lwkt_port *cdevport[NUMCDEVSW];  
   
 static int cdevsw_putport(lwkt_port_t port, lwkt_msg_t msg);  static int cdevsw_putport(lwkt_port_t port, lwkt_msg_t msg);
   
   struct cdevsw dead_cdevsw;
   
 /*  /*
  * Initialize a message port to serve as the default message-handling port   * Initialize a message port to serve as the default message-handling port
  * for device operations.  This message port provides compatibility with   * for device operations.  This message port provides compatibility with
Line 69  int Line 70  int
 cdevsw_putport(lwkt_port_t port, lwkt_msg_t lmsg)  cdevsw_putport(lwkt_port_t port, lwkt_msg_t lmsg)
 {  {
     cdevallmsg_t msg = (cdevallmsg_t)lmsg;      cdevallmsg_t msg = (cdevallmsg_t)lmsg;
     struct cdevsw *csw = msg->am_msg.csw;      struct cdevsw *devsw = msg->am_msg.dev->si_devsw;
     int error;      int error;
   
     /*      /*
Line 78  cdevsw_putport(lwkt_port_t port, lwkt_ms Line 79  cdevsw_putport(lwkt_port_t port, lwkt_ms
      */       */
     switch(msg->am_lmsg.ms_cmd.cm_op) {      switch(msg->am_lmsg.ms_cmd.cm_op) {
     case CDEV_CMD_OPEN:      case CDEV_CMD_OPEN:
         error = csw->old_open(          error = devsw->old_open(
                     msg->am_open.msg.dev,                      msg->am_open.msg.dev,
                     msg->am_open.oflags,                      msg->am_open.oflags,
                     msg->am_open.devtype,                      msg->am_open.devtype,
                     msg->am_open.td);                      msg->am_open.td);
         break;          break;
     case CDEV_CMD_CLOSE:      case CDEV_CMD_CLOSE:
         error = csw->old_close(          error = devsw->old_close(
                     msg->am_close.msg.dev,                      msg->am_close.msg.dev,
                     msg->am_close.fflag,                      msg->am_close.fflag,
                     msg->am_close.devtype,                      msg->am_close.devtype,
                     msg->am_close.td);                      msg->am_close.td);
         break;          break;
     case CDEV_CMD_STRATEGY:      case CDEV_CMD_STRATEGY:
         csw->old_strategy(msg->am_strategy.bp);          devsw->old_strategy(msg->am_strategy.bp);
         error = 0;          error = 0;
         break;          break;
     case CDEV_CMD_IOCTL:      case CDEV_CMD_IOCTL:
         error = csw->old_ioctl(          error = devsw->old_ioctl(
                     msg->am_ioctl.msg.dev,                      msg->am_ioctl.msg.dev,
                     msg->am_ioctl.cmd,                      msg->am_ioctl.cmd,
                     msg->am_ioctl.data,                      msg->am_ioctl.data,
Line 104  cdevsw_putport(lwkt_port_t port, lwkt_ms Line 105  cdevsw_putport(lwkt_port_t port, lwkt_ms
                     msg->am_ioctl.td);                      msg->am_ioctl.td);
         break;          break;
     case CDEV_CMD_DUMP:      case CDEV_CMD_DUMP:
         error = csw->old_dump(msg->am_ioctl.msg.dev);          error = devsw->old_dump(
                       msg->am_dump.msg.dev,
                       msg->am_dump.count,
                       msg->am_dump.blkno,
                       msg->am_dump.secsize);
         break;          break;
     case CDEV_CMD_PSIZE:      case CDEV_CMD_PSIZE:
         msg->am_psize.result = csw->old_psize(msg->am_psize.msg.dev);          msg->am_psize.result = devsw->old_psize(msg->am_psize.msg.dev);
         error = 0;      /* XXX */          error = 0;      /* XXX */
         break;          break;
     case CDEV_CMD_READ:      case CDEV_CMD_READ:
         error = csw->old_read(          error = devsw->old_read(
                     msg->am_read.msg.dev,                      msg->am_read.msg.dev,
                     msg->am_read.uio,                      msg->am_read.uio,
                     msg->am_read.ioflag);                      msg->am_read.ioflag);
         break;          break;
     case CDEV_CMD_WRITE:      case CDEV_CMD_WRITE:
         error = csw->old_write(          error = devsw->old_write(
                     msg->am_read.msg.dev,                      msg->am_read.msg.dev,
                     msg->am_read.uio,                      msg->am_read.uio,
                     msg->am_read.ioflag);                      msg->am_read.ioflag);
         break;          break;
     case CDEV_CMD_POLL:      case CDEV_CMD_POLL:
         msg->am_poll.events = csw->old_poll(          msg->am_poll.events = devsw->old_poll(
                                 msg->am_poll.msg.dev,                                  msg->am_poll.msg.dev,
                                 msg->am_poll.events,                                  msg->am_poll.events,
                                 msg->am_poll.td);                                  msg->am_poll.td);
         error = 0;          error = 0;
         break;          break;
     case CDEV_CMD_KQFILTER:      case CDEV_CMD_KQFILTER:
         msg->am_kqfilter.result = csw->old_kqfilter(          msg->am_kqfilter.result = devsw->old_kqfilter(
                                 msg->am_kqfilter.msg.dev,                                  msg->am_kqfilter.msg.dev,
                                 msg->am_kqfilter.kn);                                  msg->am_kqfilter.kn);
         error = 0;          error = 0;
         break;          break;
     case CDEV_CMD_MMAP:      case CDEV_CMD_MMAP:
         msg->am_mmap.result = csw->old_mmap(          msg->am_mmap.result = devsw->old_mmap(
                     msg->am_mmap.msg.dev,                      msg->am_mmap.msg.dev,
                     msg->am_mmap.offset,                      msg->am_mmap.offset,
                     msg->am_mmap.nprot);                      msg->am_mmap.nprot);
Line 150  cdevsw_putport(lwkt_port_t port, lwkt_ms Line 155  cdevsw_putport(lwkt_port_t port, lwkt_ms
     return(error);      return(error);
 }  }
   
 /*  
  * These device dispatch functions provide convenient entry points for  
  * any code wishing to make a dev call.  
  *  
  * YYY we ought to be able to optimize the port lookup by caching it in  
  * the dev_t structure itself.  
  */  
 static __inline  
 struct cdevsw *  
 _devsw(dev_t dev)  
 {  
     if (dev == NULL)  
         return(NULL);  
     if (dev->si_devsw)  
         return (dev->si_devsw);  
     return(cdevsw[major(dev)]);  
 }  
   
 static __inline  static __inline
 lwkt_port_t  lwkt_port_t
 _init_cdevmsg(dev_t dev, cdevmsg_t msg, int cmd)  _init_cdevmsg(dev_t dev, cdevmsg_t msg, int cmd)
 {  {
     struct cdevsw *csw;  
   
     lwkt_initmsg_simple(&msg->msg, cmd);      lwkt_initmsg_simple(&msg->msg, cmd);
     msg->dev = dev;      msg->dev = dev;
     msg->csw = csw = _devsw(dev);      return(dev->si_port);
     if (csw != NULL) {                  /* YYY too hackish */  
         KKASSERT(csw->d_port);          /* YYY too hackish */  
         if (cdevport[major(dev)])       /* YYY too hackish */  
             return(cdevport[major(dev)]);  
         return(csw->d_port);  
     }  
     return(NULL);  
 }  }
   
 int  int
Line 244  dev_dioctl(dev_t dev, u_long cmd, caddr_ Line 222  dev_dioctl(dev_t dev, u_long cmd, caddr_
     return(lwkt_domsg(port, &msg.msg.msg));      return(lwkt_domsg(port, &msg.msg.msg));
 }  }
   
   /*
    * note: the disk layer is expected to set count, blkno, and secsize before
    * forwarding the message.
    */
 int  int
 dev_ddump(dev_t dev)  dev_ddump(dev_t dev)
 {  {
Line 253  dev_ddump(dev_t dev) Line 235  dev_ddump(dev_t dev)
     port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);      port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
     if (port == NULL)      if (port == NULL)
         return(ENXIO);          return(ENXIO);
       msg.count = 0;
       msg.blkno = 0;
       msg.secsize = 0;
     return(lwkt_domsg(port, &msg.msg.msg));      return(lwkt_domsg(port, &msg.msg.msg));
 }  }
   
Line 353  dev_dmmap(dev_t dev, vm_offset_t offset, Line 338  dev_dmmap(dev_t dev, vm_offset_t offset,
     return(-1);      return(-1);
 }  }
   
 int  
 dev_port_dopen(lwkt_port_t port, dev_t dev, int oflags, int devtype, thread_t td)  
 {  
     struct cdevmsg_open msg;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);  
     if (port == NULL)  
         return(ENXIO);  
     msg.oflags = oflags;  
     msg.devtype = devtype;  
     msg.td = td;  
     return(lwkt_domsg(port, &msg.msg.msg));  
 }  
   
 int  
 dev_port_dclose(lwkt_port_t port, dev_t dev, int fflag, int devtype, thread_t td)  
 {  
     struct cdevmsg_close msg;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);  
     if (port == NULL)  
         return(ENXIO);  
     msg.fflag = fflag;  
     msg.devtype = devtype;  
     msg.td = td;  
     return(lwkt_domsg(port, &msg.msg.msg));  
 }  
   
 void  
 dev_port_dstrategy(lwkt_port_t port, dev_t dev, struct buf *bp)  
 {  
     struct cdevmsg_strategy msg;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);  
     KKASSERT(port);     /* 'nostrategy' function is NULL YYY */  
     msg.bp = bp;  
     lwkt_domsg(port, &msg.msg.msg);  
 }  
   
 int  
 dev_port_dioctl(lwkt_port_t port, dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)  
 {  
     struct cdevmsg_ioctl msg;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);  
     if (port == NULL)  
         return(ENXIO);  
     msg.cmd = cmd;  
     msg.data = data;  
     msg.fflag = fflag;  
     msg.td = td;  
     return(lwkt_domsg(port, &msg.msg.msg));  
 }  
   
 int  
 dev_port_ddump(lwkt_port_t port, dev_t dev)  
 {  
     struct cdevmsg_dump msg;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);  
     if (port == NULL)  
         return(ENXIO);  
     return(lwkt_domsg(port, &msg.msg.msg));  
 }  
   
 int  
 dev_port_dpsize(lwkt_port_t port, dev_t dev)  
 {  
     struct cdevmsg_psize msg;  
     int error;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);  
     if (port == NULL)  
         return(-1);  
     error = lwkt_domsg(port, &msg.msg.msg);  
     if (error == 0)  
         return(msg.result);  
     return(-1);  
 }  
   
 int  
 dev_port_dread(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)  
 {  
     struct cdevmsg_read msg;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);  
     if (port == NULL)  
         return(ENXIO);  
     msg.uio = uio;  
     msg.ioflag = ioflag;  
     return(lwkt_domsg(port, &msg.msg.msg));  
 }  
   
 int  
 dev_port_dwrite(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)  
 {  
     struct cdevmsg_write msg;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);  
     if (port == NULL)  
         return(ENXIO);  
     msg.uio = uio;  
     msg.ioflag = ioflag;  
     return(lwkt_domsg(port, &msg.msg.msg));  
 }  
   
 int  
 dev_port_dpoll(lwkt_port_t port, dev_t dev, int events, thread_t td)  
 {  
     struct cdevmsg_poll msg;  
     int error;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);  
     if (port == NULL)  
         return(ENXIO);  
     msg.events = events;  
     msg.td = td;  
     error = lwkt_domsg(port, &msg.msg.msg);  
     if (error == 0)  
         return(msg.events);  
     return(seltrue(dev, msg.events, td));  
 }  
   
 int  
 dev_port_dkqfilter(lwkt_port_t port, dev_t dev, struct knote *kn)  
 {  
     struct cdevmsg_kqfilter msg;  
     int error;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);  
     if (port == NULL)  
         return(ENXIO);  
     msg.kn = kn;  
     error = lwkt_domsg(port, &msg.msg.msg);  
     if (error == 0)  
         return(msg.result);  
     return(ENODEV);  
 }  
   
 int  
 dev_port_dmmap(lwkt_port_t port, dev_t dev, vm_offset_t offset, int nprot)  
 {  
     struct cdevmsg_mmap msg;  
     int error;  
   
     _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);  
     if (port == NULL)  
         return(-1);  
     msg.offset = offset;  
     msg.nprot = nprot;  
     error = lwkt_domsg(port, &msg.msg.msg);  
     if (error == 0)  
         return(msg.result);  
     return(-1);  
 }  
   
 const char *  const char *
 dev_dname(dev_t dev)  dev_dname(dev_t dev)
 {  {
     struct cdevsw *csw;      return(dev->si_devsw->d_name);
   
     if ((csw = _devsw(dev)) != NULL)  
         return(csw->d_name);  
     return(NULL);  
 }  }
   
 int  int
 dev_dflags(dev_t dev)  dev_dflags(dev_t dev)
 {  {
     struct cdevsw *csw;      return(dev->si_devsw->d_flags);
   
     if ((csw = _devsw(dev)) != NULL)  
         return(csw->d_flags);  
     return(0);  
 }  }
   
 int  int
 dev_dmaj(dev_t dev)  dev_dmaj(dev_t dev)
 {  {
     struct cdevsw *csw;      return(dev->si_devsw->d_maj);
   
     if ((csw = _devsw(dev)) != NULL)  
         return(csw->d_maj);  
     return(0);  
 }  }
   
 lwkt_port_t  lwkt_port_t
 dev_dport(dev_t dev)  dev_dport(dev_t dev)
 {  {
     struct cdevsw *csw;      return(dev->si_port);
   
     if ((csw = _devsw(dev)) != NULL) {  
         if (cdevport[major(dev)])       /* YYY too hackish */  
             return(cdevport[major(dev)]);  
         return(csw->d_port);  
     }  
     return(NULL);  
 }  }
   
 #if 0  
 /*  
  * cdevsw[] array functions, moved from kern/kern_conf.c  
  */  
 struct cdevsw *  
 devsw(dev_t dev)  
 {  
     return(_devsw(dev));  
 }  
 #endif  
   
 /*  /*
  * Convert a cdevsw template into the real thing, filling in fields the   * Convert a cdevsw template into the real thing, filling in fields the
  * device left empty with appropriate defaults.   * device left empty with appropriate defaults.
Line 600  compile_devsw(struct cdevsw *devsw) Line 399  compile_devsw(struct cdevsw *devsw)
   
     if (devsw->d_port == NULL)      if (devsw->d_port == NULL)
         devsw->d_port = &devsw_compat_port;          devsw->d_port = &devsw_compat_port;
       if (devsw->d_clone == NULL)
           devsw->d_clone = noclone;
 }  }
   
 /*  /*
  * Add a cdevsw entry   * This makes a cdevsw entry visible to userland (e.g /dev/<blah>).
    *
    * The kernel can overload a major number with multiple cdevsw's but only
    * the one installed in cdevbase[] is visible to userland.  make_dev() does
    * not automatically call cdevsw_add() (nor do we want it to, since 
    * partition-managed disk devices are overloaded on top of the raw device).
  */   */
 int  int
 cdevsw_add(struct cdevsw *newentry)  cdevsw_add(struct cdevsw *devsw, u_int mask, u_int match)
 {  {
     compile_devsw(newentry);      int maj;
     if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {      struct cdevlink *link;
   
       compile_devsw(devsw);
       maj = devsw->d_maj;
       if (maj < 0 || maj >= NUMCDEVSW) {
         printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",          printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
             newentry->d_name, newentry->d_maj);              devsw->d_name, maj);
         return (EINVAL);          return (EINVAL);
     }      }
     if (cdevsw[newentry->d_maj]) {      for (link = cdevbase[maj]; link; link = link->next) {
         printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",          /*
             newentry->d_name, cdevsw[newentry->d_maj]->d_name);           * If we get an exact match we usurp the target, but we only print
            * a warning message if a different device switch is installed.
            */
           if (link->mask == mask && link->match == match) {
               if (link->devsw != devsw) {
                       printf("WARNING: \"%s\" (%p) is usurping \"%s\"'s (%p)"
                           " cdevsw[]\n",
                           devsw->d_name, devsw, 
                           link->devsw->d_name, link->devsw);
                       link->devsw = devsw;
                       ++devsw->d_refs;
               }
               return(0);
           }
           /*
            * XXX add additional warnings for overlaps
            */
     }      }
     cdevsw[newentry->d_maj] = newentry;  
     return (0);      link = malloc(sizeof(struct cdevlink), M_DEVBUF, M_INTWAIT|M_ZERO);
       link->mask = mask;
       link->match = match;
       link->devsw = devsw;
       link->next = cdevbase[maj];
       cdevbase[maj] = link;
       ++devsw->d_refs;
       return(0);
 }  }
   
 /*  /*
  * Add a cdevsw entry and override the port.   * Should only be used by udev2dev().
    *
    * If the minor number is -1, we match the first cdevsw we find for this
    * major. 
    *
    * Note that this function will return NULL if the minor number is not within
    * the bounds of the installed mask(s).
  */   */
 lwkt_port_t  struct cdevsw *
 cdevsw_add_override(struct cdevsw *newentry, lwkt_port_t port)  cdevsw_get(int x, int y)
 {  {
     int error;      struct cdevlink *link;
   
     if ((error = cdevsw_add(newentry)) == 0)      if (x < 0 || x >= NUMCDEVSW)
         cdevport[newentry->d_maj] = port;          return(NULL);
     return(newentry->d_port);      for (link = cdevbase[x]; link; link = link->next) {
           if (y == -1 || (link->mask & y) == link->match)
               return(link->devsw);
       }
       return(NULL);
   }
   
   /*
    * Use the passed cdevsw as a template to create our intercept cdevsw,
    * and install and return ours.
    */
   struct cdevsw *
   cdevsw_add_override(dev_t backing_dev, u_int mask, u_int match)
   {
       struct cdevsw *devsw;
       struct cdevsw *bsw = backing_dev->si_devsw;
   
       devsw = malloc(sizeof(struct cdevsw), M_DEVBUF, M_INTWAIT|M_ZERO);
       devsw->d_name = bsw->d_name;
       devsw->d_maj = bsw->d_maj;
       devsw->d_flags = bsw->d_flags;
       compile_devsw(devsw);
       cdevsw_add(devsw, mask, match);
   
       return(devsw);
 }  }
   
   /*
    * Override a device's port, returning the previously installed port.  This
    * is XXX very dangerous.
    */
 lwkt_port_t  lwkt_port_t
 cdevsw_dev_override(dev_t dev, lwkt_port_t port)  cdevsw_dev_override(dev_t dev, lwkt_port_t port)
 {  {
     struct cdevsw *csw;      lwkt_port_t oport;
   
     KKASSERT(major(dev) >= 0 && major(dev) < NUMCDEVSW);      oport = dev->si_port;
     if ((csw = _devsw(dev)) != NULL) {      dev->si_port = port;
         cdevport[major(dev)] = port;      return(oport);
         return(csw->d_port);  
     }  
     return(NULL);  
 }  }
   
 /*  /*
  *  Remove a cdevsw entry   * Remove a cdevsw entry from the cdevbase[] major array so no new user opens
    * can be performed, and destroy all devices installed in the hash table
    * which are associated with this cdevsw.  (see destroy_all_dev()).
  */   */
 int  int
 cdevsw_remove(struct cdevsw *oldentry)  cdevsw_remove(struct cdevsw *devsw, u_int mask, u_int match)
 {  {
     if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {      int maj = devsw->d_maj;
       struct cdevlink *link;
       struct cdevlink **plink;
    
       if (maj < 0 || maj >= NUMCDEVSW) {
         printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",          printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
             oldentry->d_name, oldentry->d_maj);              devsw->d_name, maj);
         return EINVAL;          return EINVAL;
     }      }
     cdevsw[oldentry->d_maj] = NULL;      if (devsw != &dead_cdevsw)
     cdevport[oldentry->d_maj] = NULL;          destroy_all_dev(devsw, mask, match);
       for (plink = &cdevbase[maj]; (link = *plink) != NULL; plink = &link->next) {
           if (link->mask == mask && link->match == match) {
               if (link->devsw == devsw)
                   break;
               printf("%s: ERROR: cannot remove from cdevsw[], its major"
                       " number %d was stolen by %s\n",
                       devsw->d_name, maj,
                       link->devsw->d_name
               );
           }
       }
       if (link == NULL) {
           printf("%s(%d): WARNING: cdevsw removed multiple times!\n",
                   devsw->d_name, maj);
       } else {
           *plink = link->next;
           --devsw->d_refs; /* XXX cdevsw_release() / record refs */
           free(link, M_DEVBUF);
       }
       if (devsw->d_refs != 0) {
           printf("%s: Warning: cdevsw_remove() called while %d device refs"
                   " still exist! (major %d)\n", 
                   devsw->d_name,
                   devsw->d_refs,
                   maj);
       } else {
           printf("%s: cdevsw removed\n", devsw->d_name);
       }
     return 0;      return 0;
 }  }
   
   /*
    * Release a cdevsw entry.  When the ref count reaches zero, recurse
    * through the stack.
    */
   void
   cdevsw_release(struct cdevsw *devsw)
   {
       --devsw->d_refs;
       if (devsw->d_refs == 0) {
           /* XXX */
       }
   }
   

Removed from v.1.10  
changed lines
  Added in v.1.11