The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_drvctl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $NetBSD: kern_drvctl.c,v 1.9 2006/11/01 10:17:58 yamt Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2004
    5  *      Matthias Drochner.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions, and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.9 2006/11/01 10:17:58 yamt Exp $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/conf.h>
   36 #include <sys/device.h>
   37 #include <sys/event.h>
   38 #include <sys/malloc.h>
   39 #include <sys/ioctl.h>
   40 #include <sys/fcntl.h>
   41 #include <sys/drvctlio.h>
   42 
   43 dev_type_ioctl(drvctlioctl);
   44 
   45 const struct cdevsw drvctl_cdevsw = {
   46         nullopen, nullclose, nullread, nullwrite, drvctlioctl,
   47         nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
   48 };
   49 
   50 void drvctlattach(int);
   51 
   52 #define MAXLOCATORS 100
   53 
   54 static int drvctl_command(struct lwp *, struct plistref *, u_long, int flag);
   55 
   56 static int
   57 detachdevbyname(const char *devname)
   58 {
   59         struct device *d;
   60 
   61         TAILQ_FOREACH(d, &alldevs, dv_list) {
   62                 if (!strcmp(devname, d->dv_xname)) {
   63 #ifndef XXXFULLRISK
   64                         /*
   65                          * If the parent cannot be notified, it might keep
   66                          * pointers to the detached device.
   67                          * There might be a private notification mechanism,
   68                          * but better play save here.
   69                          */
   70                         if (d->dv_parent &&
   71                             !d->dv_parent->dv_cfattach->ca_childdetached)
   72                                 return (ENOTSUP);
   73 #endif
   74                         return (config_detach(d, 0));
   75                 }
   76         }
   77 
   78         return (ENXIO);
   79 }
   80 
   81 static int
   82 rescanbus(const char *busname, const char *ifattr,
   83           int numlocators, const int *locators)
   84 {
   85         int i;
   86         struct device *d;
   87         const struct cfiattrdata * const *ap;
   88 
   89         /* XXX there should be a way to get limits and defaults (per device)
   90            from config generated data */
   91         int locs[MAXLOCATORS];
   92         for (i = 0; i < MAXLOCATORS; i++)
   93                 locs[i] = -1;
   94 
   95         for (i = 0; i < numlocators;i++)
   96                 locs[i] = locators[i];
   97 
   98         TAILQ_FOREACH(d, &alldevs, dv_list) {
   99                 if (!strcmp(busname, d->dv_xname)) {
  100                         /*
  101                          * must support rescan, and must have something
  102                          * to attach to
  103                          */
  104                         if (!d->dv_cfattach->ca_rescan ||
  105                             !d->dv_cfdriver->cd_attrs)
  106                                 return (ENODEV);
  107 
  108                         /* allow to omit attribute if there is exactly one */
  109                         if (!ifattr) {
  110                                 if (d->dv_cfdriver->cd_attrs[1])
  111                                         return (EINVAL);
  112                                 ifattr = d->dv_cfdriver->cd_attrs[0]->ci_name;
  113                         } else {
  114                                 /* check for valid attribute passed */
  115                                 for (ap = d->dv_cfdriver->cd_attrs; *ap; ap++)
  116                                         if (!strcmp((*ap)->ci_name, ifattr))
  117                                                 break;
  118                                 if (!*ap)
  119                                         return (EINVAL);
  120                         }
  121 
  122                         return (*d->dv_cfattach->ca_rescan)(d, ifattr, locs);
  123                 }
  124         }
  125 
  126         return (ENXIO);
  127 }
  128 
  129 int
  130 drvctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *p)
  131 {
  132         int res;
  133         char *ifattr;
  134         int *locs;
  135 
  136         switch (cmd) {
  137         case DRVDETACHDEV:
  138 #define d ((struct devdetachargs *)data)
  139                 res = detachdevbyname(d->devname);
  140 #undef d
  141                 break;
  142         case DRVRESCANBUS:
  143 #define d ((struct devrescanargs *)data)
  144                 d->busname[sizeof(d->busname) - 1] = '\0';
  145 
  146                 /* XXX better copyin? */
  147                 if (d->ifattr[0]) {
  148                         d->ifattr[sizeof(d->ifattr) - 1] = '\0';
  149                         ifattr = d->ifattr;
  150                 } else
  151                         ifattr = 0;
  152 
  153                 if (d->numlocators) {
  154                         if (d->numlocators > MAXLOCATORS)
  155                                 return (EINVAL);
  156                         locs = malloc(d->numlocators * sizeof(int), M_DEVBUF,
  157                                       M_WAITOK);
  158                         res = copyin(d->locators, locs,
  159                                      d->numlocators * sizeof(int));
  160                         if (res)
  161                                 return (res);
  162                 } else
  163                         locs = 0;
  164                 res = rescanbus(d->busname, ifattr, d->numlocators, locs);
  165                 if (locs)
  166                         free(locs, M_DEVBUF);
  167 #undef d
  168                 break;
  169         case DRVCTLCOMMAND:
  170                 res = drvctl_command(p, (struct plistref *)data, cmd, flag);
  171                 break;
  172         default:
  173                 return (EPASSTHROUGH);
  174         }
  175         return (res);
  176 }
  177 
  178 void
  179 drvctlattach(int arg)
  180 {
  181 }
  182 
  183 /*****************************************************************************
  184  * Driver control command processing engine
  185  *****************************************************************************/
  186 
  187 static int
  188 drvctl_command_get_properties(struct lwp *l,
  189                               prop_dictionary_t command_dict,
  190                               prop_dictionary_t results_dict)
  191 {
  192         prop_dictionary_t args_dict;
  193         prop_string_t devname_string;
  194         device_t dev;
  195         
  196         args_dict = prop_dictionary_get(command_dict, "drvctl-arguments");
  197         if (args_dict == NULL)
  198                 return (EINVAL);
  199 
  200         devname_string = prop_dictionary_get(args_dict, "device-name");
  201         if (devname_string == NULL)
  202                 return (EINVAL);
  203         
  204         TAILQ_FOREACH(dev, &alldevs, dv_list) {
  205                 if (prop_string_equals_cstring(devname_string,
  206                                                device_xname(dev)))
  207                         break;
  208         }
  209 
  210         if (dev == NULL)
  211                 return (ESRCH);
  212         
  213         prop_dictionary_set(results_dict, "drvctl-result-data",
  214                             device_properties(dev));
  215         
  216         return (0);
  217 }
  218 
  219 struct drvctl_command_desc {
  220         const char *dcd_name;           /* command name */
  221         int (*dcd_func)(struct lwp *,   /* handler function */
  222                         prop_dictionary_t,
  223                         prop_dictionary_t);
  224         int dcd_rw;                     /* read or write required */
  225 };
  226 
  227 static const struct drvctl_command_desc drvctl_command_table[] = {
  228         { .dcd_name = "get-properties",
  229           .dcd_func = drvctl_command_get_properties,
  230           .dcd_rw   = FREAD,
  231         },
  232 
  233         { .dcd_name = NULL }
  234 };
  235 
  236 static int
  237 drvctl_command(struct lwp *l, struct plistref *pref, u_long ioctl_cmd,
  238                int fflag)
  239 {
  240         prop_dictionary_t command_dict, results_dict;
  241         prop_string_t command_string;
  242         const struct drvctl_command_desc *dcd;
  243         int error;
  244 
  245         error = prop_dictionary_copyin_ioctl(pref, ioctl_cmd, &command_dict);
  246         if (error)
  247                 return (error);
  248 
  249         results_dict = prop_dictionary_create();
  250         if (results_dict == NULL) {
  251                 prop_object_release(command_dict);
  252                 return (ENOMEM);
  253         }
  254         
  255         command_string = prop_dictionary_get(command_dict, "drvctl-command");
  256         if (command_string == NULL) {
  257                 error = EINVAL;
  258                 goto out;
  259         }
  260 
  261         for (dcd = drvctl_command_table; dcd->dcd_name != NULL; dcd++) {
  262                 if (prop_string_equals_cstring(command_string,
  263                                                dcd->dcd_name))
  264                         break;
  265         }
  266 
  267         if (dcd->dcd_name == NULL) {
  268                 error = EINVAL;
  269                 goto out;
  270         }
  271 
  272         if ((fflag & dcd->dcd_rw) == 0) {
  273                 error = EPERM;
  274                 goto out;
  275         }
  276 
  277         error = (*dcd->dcd_func)(l, command_dict, results_dict);
  278 
  279         prop_dictionary_set_int32(results_dict, "drvctl-error", error);
  280 
  281         error = prop_dictionary_copyout_ioctl(pref, ioctl_cmd, results_dict);
  282  out:
  283         prop_object_release(command_dict);
  284         prop_object_release(results_dict);
  285         return (error);
  286 }

Cache object: 007f178c9b745a1b8b324e66872b5e65


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.