1 Reply Latest reply: Dec 3, 2008 11:24 PM by 807567 RSS

    IOCTL from user level program do not reach module

    807567
      Hello,

      I am facing with a weired problem. The user level ioctl on my device file does not reach the ioctl handler in my module at all. I have a simple character device driver called dummy (just pulled from a device driver manual 'hello world' example).

      root@/modinfo | grep dummy
      227 fa2f9a20 634 220 1 dummy (dummy driver)
      root@/ls -l /devices/pseudo/dummy\@0\:0
      c-wxrw--wx 1 root sys 220, 0 Dec 3 15:13 /devices/pseudo/dummy@0:0

      The open on the device file works well. But when I call ioctl, the message in the ioctl handler does not print. Niether does the ioctl call appear in the DTrace probes. perror from user program returns :

      : Invalid argument

      Let me know of any probable cause of ioctls not getting executed.

      Thanks in advance
      ->Shreyas

      My driver code is as follows :
      /*
          * Minimalist pseudo-device.
          * Writes a message whenever a routine is entered.
          *
          * Build the driver:
          *         cc -D_KERNEL -c dummy.c
          *         ld -r -o dummy dummy.o
          * Copy the driver and the configuration file to /usr/kernel/drv:
          *         cp dummy.conf /usr/kernel/drv
          *         cp dummy /tmp
          *         ln -s /tmp/dummy /usr/kernel/drv/dummy
          * Add the driver:
          *         add_drv dummy
          * Test (1) read from driver (2) write to driver:
          *         cat /devices/pseudo/dummy@*
                    echo hello > ‘ls /devices/pseudo/dummy@*‘
          *
          * Verify the tests in another window:
          *         tail -f /var/adm/messages
          * Remove the driver:
          *         rem_drv dummy
          */
      #define SOLARIS
      #include <sys/devops.h> /* used by dev_ops */
      #include <sys/conf.h>               /* used by dev_ops and cb_ops */
      #include <sys/modctl.h> /* used by modlinkage, modldrv, _init, _info, */
                                             /* and _fini */
      #include <sys/types.h> /* used by open, close, read, write, prop_op, */
                                             /* and ddi_prop_op */
      #include <sys/file.h>               /* used by open, close */
      #include <sys/errno.h> /* used by open, close, read, write */
      #include    <sys/open.h>         /* used by open, close, read, write */
      #include    <sys/cred.h>         /* used by open, close, read */
      #include    <sys/uio.h>          /* used by read */
      #include    <sys/stat.h>         /* defines S_IFCHR used by ddi_create_minor_node */
      #include    <sys/cmn_err.h>      /* used by all entry points for this driver */
      #include    <sys/ddi.h>          /* used by all entry points for this driver */
                                       /* also used by cb_ops, ddi_get_instance, and */
                                       /* ddi_prop_op */
      #include <sys/sunddi.h> /*          used by all entry points for this driver */
                                       /* also used by cb_ops, ddi_create_minor_node, */
                                       /* ddi_get_instance, and ddi_prop_op */
      #include "vmci_defs.h"
      #include "vmciDatagram.h"
       
      char _depends_on[]="vmci";
       
      static int dummy_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
      static int dummy_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
      static int dummy_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
           void **resultp);
      static int dummy_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
           int flags, char *name, caddr_t valuep, int *lengthp);
      static int dummy_open(dev_t *devp, int flag, int otyp, cred_t *cred);
      static int dummy_close(dev_t dev, int flag, int otyp, cred_t *cred);
      static int dummy_read(dev_t dev, struct uio *uiop, cred_t *credp);
      static int dummy_write(dev_t dev, struct uio *uiop, cred_t *credp);
      static int dummy_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
                            cred_t *credp, int *rval);
      static int dummy_poll(dev_t dev, short events, int anyyet,
                            short *reventsp, struct pollhead **phpp);
       
      /* cb_ops structure */
      static struct cb_ops dummy_cb_ops = {
           dummy_open,
           dummy_close,
           nodev,                     /* no strategy - nodev returns ENXIO */
           nodev,                     /* no print */
           nodev,                     /* no dump */
           dummy_read,
           dummy_write,
           dummy_ioctl,
           nodev,                     /* no devmap */
           nodev,                     /* no mmap */
           nodev,                     /* no segmap */
           dummy_poll,                /* returns ENXIO for non-pollable devices */
           dummy_prop_op,
           NULL,                      /* streamtab struct; if not NULL, all above */
                                      /* fields are ignored */
           D_NEW | D_MP,              /* compatibility flags: see conf.h */
           CB_REV,                    /* cb_ops revision number */
           nodev,                     /* no aread */
           nodev                      /* no awrite */
      };
      /* dev_ops structure */
      static struct dev_ops dummy_dev_ops = {
           DEVO_REV,
           0,                            /* reference count */
           ddi_no_info,
           //dummy_getinfo,
           nulldev,                      /* no identify - nulldev returns 0 */
           nulldev,                      /* no probe */
           dummy_attach,
           dummy_detach,
           nodev,                        /* no reset - nodev returns ENXIO */
           &dummy_cb_ops,
           (struct bus_ops *)NULL,
           NULL                         /* no power */
      };
      /* modldrv structure */
      static struct modldrv md = {
           &mod_driverops,               /* Type of module. This is a driver. */
           "dummy driver",              /* Name of the module. */
           &dummy_dev_ops
      };
       
      /* modlinkage structure */
      static struct modlinkage ml = {
           MODREV_1,
           &md,
           NULL
      };
       
      /* dev_info structure */
      dev_info_t *dummy_dip; /* keep track of one instance */
       
      /* Loadable module configuration entry points */
      int
      _init(void)
      {
           cmn_err(CE_NOTE, "Inside _init");
           return(mod_install(&ml));
      }
      int
      _info(struct modinfo *modinfop)
      {
           cmn_err(CE_NOTE, "Inside _info");
           return(mod_info(&ml, modinfop));
      }
      int
      _fini(void)
      {
           cmn_err(CE_NOTE, "Inside _fini");
           return(mod_remove(&ml));
      }
      /* Device configuration entry points */
      static int
      dummy_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
      {
           cmn_err(CE_NOTE, "Inside dummy_attach");
           switch(cmd) {
           case DDI_ATTACH:
                 dummy_dip = dip;
                 if (ddi_create_minor_node(dip, "0", S_IFCHR,
                     ddi_get_instance(dip), DDI_PSEUDO,0)
                     != DDI_SUCCESS) {
                     cmn_err(CE_NOTE,
                           "%s%d: attach: could not add character node.",
                           "dummy", 0);
                     return(DDI_FAILURE);
                 } else
                     return DDI_SUCCESS;
           default:
                 return DDI_FAILURE;
           }
      }
      static int
      dummy_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
      {
           cmn_err(CE_NOTE, "Inside dummy_detach");
           switch(cmd) {
           case DDI_DETACH:
                 dummy_dip = 0;
                 ddi_remove_minor_node(dip, NULL);
                 return DDI_SUCCESS;
           default:
                 return DDI_FAILURE;
           }
      }
      static int
      dummy_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
           void **resultp)
      {
           cmn_err(CE_NOTE, "Inside dummy_getinfo");
           switch(cmd) {
           case DDI_INFO_DEVT2DEVINFO:
                                       *resultp = dummy_dip;
                                       return DDI_SUCCESS;
                                   case DDI_INFO_DEVT2INSTANCE:
                                       *resultp = 0;
                                       return DDI_SUCCESS;
                                   default:
                                       return DDI_FAILURE;
                                   }
                              }
      /* Main entry points */
      static int
      dummy_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
        int flags, char *name, caddr_t valuep, int *lengthp)
      {
        cmn_err(CE_NOTE, "Inside dummy_prop_op");
      //  return DDI_SUCCESS;
        return(ddi_prop_op(dev,dip,prop_op,flags,name,valuep,lengthp));
      }
       
      static int
      dummy_open(dev_t *devp, int flag, int otyp, cred_t *cred)
      {
         int status;
       
         cmn_err(CE_NOTE, "Inside dummy_open");
       
          return DDI_SUCCESS;
      }
      static int
      dummy_close(dev_t dev, int flag, int otyp, cred_t *cred)
      {
          cmn_err(CE_NOTE, "Inside dummy_close");
          return DDI_SUCCESS;
      }
       
      static int
      dummy_read(dev_t dev, struct uio *uiop, cred_t *credp)
      {
           cmn_err(CE_NOTE, "Inside dummy_read");
           return DDI_SUCCESS;
       
      }
      static int
      dummy_write(dev_t dev, struct uio *uiop, cred_t *credp)
      {
           cmn_err(CE_NOTE, "Inside dummy_write");
           return DDI_SUCCESS;
      }
       
      static int
      dummy_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
                            cred_t *credp, int *rval)
      {
           cmn_err(CE_WARN, "%s(%d) Received function : %d\n", __FUNCTION__, __LINE__, cmd);
           return(0);
      }
       
       
      static int
      dummy_poll(dev_t dev,                // IN: Device number.
                 short events,             // IN: Requested events.
                 int anyyet,               // IN: Whether other fds have had events.
                 short *reventsp,          // OUT: Mask of satisfied events.  
                 struct pollhead **phpp) { // OUT: Set to a pollhead if necessary.
           cmn_err(CE_WARN, "%s(%d) \n", __FUNCTION__, __LINE__);
         
         return 0;
      }