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/compat/linsysfs/linsysfs.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 /*-
    2  * Copyright (c) 2006 IronPort Systems
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <sys/malloc.h>
   34 #include <sys/mount.h>
   35 #include <sys/proc.h>
   36 #include <sys/sbuf.h>
   37 #include <sys/smp.h>
   38 #include <sys/socket.h>
   39 #include <sys/bus.h>
   40 #include <sys/pciio.h>
   41 
   42 #include <dev/pci/pcivar.h>
   43 #include <dev/pci/pcireg.h>
   44 
   45 #include <net/if.h>
   46 
   47 #include <compat/linux/linux_util.h>
   48 #include <fs/pseudofs/pseudofs.h>
   49 
   50 struct scsi_host_queue {
   51         TAILQ_ENTRY(scsi_host_queue) scsi_host_next;
   52         char *path;
   53         char *name;
   54 };
   55 
   56 TAILQ_HEAD(,scsi_host_queue) scsi_host_q;
   57 
   58 static int host_number = 0;
   59 
   60 static int
   61 atoi(const char *str)
   62 {
   63         return (int)strtol(str, (char **)NULL, 10);
   64 }
   65 
   66 /*
   67  * Filler function for proc_name
   68  */
   69 static int
   70 linsysfs_scsiname(PFS_FILL_ARGS)
   71 {
   72         struct scsi_host_queue *scsi_host;
   73         int index;
   74 
   75         if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
   76                 index = atoi(&pn->pn_parent->pn_name[4]);
   77         } else {
   78                 sbuf_printf(sb, "unknown\n");
   79                 return (0);
   80         }
   81         TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
   82                 if (index-- == 0) {
   83                         sbuf_printf(sb, "%s\n", scsi_host->name);
   84                         return (0);
   85                 }
   86         }
   87         sbuf_printf(sb, "unknown\n");
   88         return (0);
   89 }
   90 
   91 /*
   92  * Filler function for device sym-link
   93  */
   94 static int
   95 linsysfs_link_scsi_host(PFS_FILL_ARGS)
   96 {
   97         struct scsi_host_queue *scsi_host;
   98         int index;
   99 
  100         if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
  101                 index = atoi(&pn->pn_parent->pn_name[4]);
  102         } else {
  103                 sbuf_printf(sb, "unknown\n");
  104                 return (0);
  105         }
  106         TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
  107                 if (index-- == 0) {
  108                         sbuf_printf(sb, "../../../devices%s", scsi_host->path);
  109                         return(0);
  110                 }
  111         }
  112         sbuf_printf(sb, "unknown\n");
  113         return (0);
  114 }
  115 
  116 static int
  117 linsysfs_fill_data(PFS_FILL_ARGS)
  118 {
  119         sbuf_printf(sb, "%s", (char *)pn->pn_data);
  120         return (0);
  121 }
  122 
  123 static int
  124 linsysfs_fill_vendor(PFS_FILL_ARGS)
  125 {
  126         sbuf_printf(sb, "0x%04x\n", pci_get_vendor((device_t)pn->pn_data));
  127         return (0);
  128 }
  129 
  130 static int
  131 linsysfs_fill_device(PFS_FILL_ARGS)
  132 {
  133         sbuf_printf(sb, "0x%04x\n", pci_get_device((device_t)pn->pn_data));
  134         return (0);
  135 }
  136 
  137 static int
  138 linsysfs_fill_subvendor(PFS_FILL_ARGS)
  139 {
  140         sbuf_printf(sb, "0x%04x\n", pci_get_subvendor((device_t)pn->pn_data));
  141         return (0);
  142 }
  143 
  144 static int
  145 linsysfs_fill_subdevice(PFS_FILL_ARGS)
  146 {
  147         sbuf_printf(sb, "0x%04x\n", pci_get_subdevice((device_t)pn->pn_data));
  148         return (0);
  149 }
  150 
  151 static int
  152 linsysfs_fill_revid(PFS_FILL_ARGS)
  153 {
  154         sbuf_printf(sb, "0x%x\n", pci_get_revid((device_t)pn->pn_data));
  155         return (0);
  156 }
  157 
  158 static int
  159 linsysfs_fill_config(PFS_FILL_ARGS)
  160 {
  161         uint8_t config[48];
  162         device_t dev;
  163         uint32_t reg;
  164 
  165         dev = (device_t)pn->pn_data;
  166         bzero(config, sizeof(config));
  167         reg = pci_get_vendor(dev);
  168         config[0] = reg;
  169         config[1] = reg >> 8;
  170         reg = pci_get_device(dev);
  171         config[2] = reg;
  172         config[3] = reg >> 8;
  173         reg = pci_get_revid(dev);
  174         config[8] = reg;
  175         reg = pci_get_subvendor(dev);
  176         config[44] = reg;
  177         config[45] = reg >> 8;
  178         reg = pci_get_subdevice(dev);
  179         config[46] = reg;
  180         config[47] = reg >> 8;
  181         sbuf_bcat(sb, config, sizeof(config));
  182         return (0);
  183 }
  184 
  185 /*
  186  * Filler function for PCI uevent file
  187  */
  188 static int
  189 linsysfs_fill_uevent_pci(PFS_FILL_ARGS)
  190 {
  191         device_t dev;
  192 
  193         dev = (device_t)pn->pn_data;
  194         sbuf_printf(sb, "DRIVER=%s\nPCI_CLASS=%X\nPCI_ID=%04X:%04X\n"
  195             "PCI_SUBSYS_ID=%04X:%04X\nPCI_SLOT_NAME=%04d:%02x:%02x.%x\n",
  196             linux_driver_get_name_dev(dev), pci_get_class(dev),
  197             pci_get_vendor(dev), pci_get_device(dev), pci_get_subvendor(dev),
  198             pci_get_subdevice(dev), pci_get_domain(dev), pci_get_bus(dev),
  199             pci_get_slot(dev), pci_get_function(dev));
  200         return (0);
  201 }
  202 
  203 /*
  204  * Filler function for drm uevent file
  205  */
  206 static int
  207 linsysfs_fill_uevent_drm(PFS_FILL_ARGS)
  208 {
  209         device_t dev;
  210         int unit;
  211 
  212         dev = (device_t)pn->pn_data;
  213         unit = device_get_unit(dev);
  214         sbuf_printf(sb,
  215             "MAJOR=226\nMINOR=%d\nDEVNAME=dri/card%d\nDEVTYPE=dri_minor\n",
  216             unit, unit);
  217         return (0);
  218 }
  219 
  220 static char *
  221 get_full_pfs_path(struct pfs_node *cur)
  222 {
  223         char *temp, *path;
  224 
  225         temp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
  226         path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
  227         path[0] = '\0';
  228 
  229         do {
  230                 snprintf(temp, MAXPATHLEN, "%s/%s", cur->pn_name, path);
  231                 strlcpy(path, temp, MAXPATHLEN);
  232                 cur = cur->pn_parent;
  233         } while (cur->pn_parent != NULL);
  234 
  235         path[strlen(path) - 1] = '\0'; /* remove extra slash */
  236         free(temp, M_TEMP);
  237         return (path);
  238 }
  239 
  240 /*
  241  * Filler function for symlink from drm char device to PCI device
  242  */
  243 static int
  244 linsysfs_fill_vgapci(PFS_FILL_ARGS)
  245 {
  246         char *path;
  247 
  248         path = get_full_pfs_path((struct pfs_node*)pn->pn_data);
  249         sbuf_printf(sb, "../../../%s", path);
  250         free(path, M_TEMP);
  251         return (0);
  252 }
  253 
  254 #define PCI_DEV "pci"
  255 #define DRMN_DEV "drmn"
  256 static int
  257 linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
  258     struct pfs_node *chardev, struct pfs_node *drm, char *path, char *prefix)
  259 {
  260         struct scsi_host_queue *scsi_host;
  261         struct pfs_node *sub_dir, *cur_file;
  262         int i, nchildren, error;
  263         device_t *children, parent;
  264         devclass_t devclass;
  265         const char *name = NULL;
  266         struct pci_devinfo *dinfo;
  267         char *device, *host, *new_path, *devname;
  268 
  269         new_path = path;
  270         devname = malloc(16, M_TEMP, M_WAITOK);
  271 
  272         parent = device_get_parent(dev);
  273         if (parent) {
  274                 devclass = device_get_devclass(parent);
  275                 if (devclass != NULL)
  276                         name = devclass_get_name(devclass);
  277                 if (name && strcmp(name, PCI_DEV) == 0) {
  278                         dinfo = device_get_ivars(dev);
  279                         if (dinfo) {
  280                                 device = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
  281                                 new_path = malloc(MAXPATHLEN, M_TEMP,
  282                                     M_WAITOK);
  283                                 new_path[0] = '\000';
  284                                 strcpy(new_path, path);
  285                                 host = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
  286                                 device[0] = '\000';
  287                                 sprintf(device, "%s:%02x:%02x.%x",
  288                                     prefix,
  289                                     dinfo->cfg.bus,
  290                                     dinfo->cfg.slot,
  291                                     dinfo->cfg.func);
  292                                 strcat(new_path, "/");
  293                                 strcat(new_path, device);
  294                                 dir = pfs_create_dir(dir, device,
  295                                     NULL, NULL, NULL, 0);
  296                                 cur_file = pfs_create_file(dir, "vendor",
  297                                     &linsysfs_fill_vendor, NULL, NULL, NULL,
  298                                     PFS_RD);
  299                                 cur_file->pn_data = (void*)dev;
  300                                 cur_file = pfs_create_file(dir, "device",
  301                                     &linsysfs_fill_device, NULL, NULL, NULL,
  302                                     PFS_RD);
  303                                 cur_file->pn_data = (void*)dev;
  304                                 cur_file = pfs_create_file(dir,
  305                                     "subsystem_vendor",
  306                                     &linsysfs_fill_subvendor, NULL, NULL, NULL,
  307                                     PFS_RD);
  308                                 cur_file->pn_data = (void*)dev;
  309                                 cur_file = pfs_create_file(dir,
  310                                     "subsystem_device",
  311                                     &linsysfs_fill_subdevice, NULL, NULL, NULL,
  312                                     PFS_RD);
  313                                 cur_file->pn_data = (void*)dev;
  314                                 cur_file = pfs_create_file(dir, "revision",
  315                                     &linsysfs_fill_revid, NULL, NULL, NULL,
  316                                     PFS_RD);
  317                                 cur_file->pn_data = (void*)dev;
  318                                 cur_file = pfs_create_file(dir, "config",
  319                                     &linsysfs_fill_config, NULL, NULL, NULL,
  320                                     PFS_RD);
  321                                 cur_file->pn_data = (void*)dev;
  322                                 cur_file = pfs_create_file(dir, "uevent",
  323                                     &linsysfs_fill_uevent_pci, NULL, NULL,
  324                                     NULL, PFS_RD);
  325                                 cur_file->pn_data = (void*)dev;
  326                                 cur_file = pfs_create_link(dir, "subsystem",
  327                                     &linsysfs_fill_data, NULL, NULL, NULL, 0);
  328                                 /* libdrm just checks that the link ends in "/pci" */
  329                                 cur_file->pn_data = "/sys/bus/pci";
  330 
  331                                 if (dinfo->cfg.baseclass == PCIC_STORAGE) {
  332                                         /* DJA only make this if needed */
  333                                         sprintf(host, "host%d", host_number++);
  334                                         strcat(new_path, "/");
  335                                         strcat(new_path, host);
  336                                         pfs_create_dir(dir, host,
  337                                             NULL, NULL, NULL, 0);
  338                                         scsi_host = malloc(sizeof(
  339                                             struct scsi_host_queue),
  340                                             M_DEVBUF, M_NOWAIT);
  341                                         scsi_host->path = malloc(
  342                                             strlen(new_path) + 1,
  343                                             M_DEVBUF, M_NOWAIT);
  344                                         scsi_host->path[0] = '\000';
  345                                         bcopy(new_path, scsi_host->path,
  346                                             strlen(new_path) + 1);
  347                                         scsi_host->name = "unknown";
  348 
  349                                         sub_dir = pfs_create_dir(scsi, host,
  350                                             NULL, NULL, NULL, 0);
  351                                         pfs_create_link(sub_dir, "device",
  352                                             &linsysfs_link_scsi_host,
  353                                             NULL, NULL, NULL, 0);
  354                                         pfs_create_file(sub_dir, "proc_name",
  355                                             &linsysfs_scsiname,
  356                                             NULL, NULL, NULL, PFS_RD);
  357                                         scsi_host->name
  358                                             = linux_driver_get_name_dev(dev);
  359                                         TAILQ_INSERT_TAIL(&scsi_host_q,
  360                                             scsi_host, scsi_host_next);
  361                                 }
  362                                 free(device, M_TEMP);
  363                                 free(host, M_TEMP);
  364                         }
  365                 }
  366 
  367                 devclass = device_get_devclass(dev);
  368                 if (devclass != NULL)
  369                         name = devclass_get_name(devclass);
  370                 else
  371                         name = NULL;
  372                 if (name != NULL && strcmp(name, DRMN_DEV) == 0 &&
  373                     device_get_unit(dev) >= 0) {
  374                         dinfo = device_get_ivars(parent);
  375                         if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) {
  376                                 pfs_create_dir(dir, "drm", NULL, NULL, NULL, 0);
  377                                 sprintf(devname, "226:%d",
  378                                     device_get_unit(dev));
  379                                 sub_dir = pfs_create_dir(chardev,
  380                                     devname, NULL, NULL, NULL, 0);
  381                                 cur_file = pfs_create_link(sub_dir,
  382                                     "device", &linsysfs_fill_vgapci, NULL,
  383                                     NULL, NULL, PFS_RD);
  384                                 cur_file->pn_data = (void*)dir;
  385                                 cur_file = pfs_create_file(sub_dir,
  386                                     "uevent", &linsysfs_fill_uevent_drm, NULL,
  387                                     NULL, NULL, PFS_RD);
  388                                 cur_file->pn_data = (void*)dev;
  389                                 sprintf(devname, "card%d",
  390                                     device_get_unit(dev));
  391                                 sub_dir = pfs_create_dir(drm,
  392                                     devname, NULL, NULL, NULL, 0);
  393                                 cur_file = pfs_create_link(sub_dir,
  394                                     "device", &linsysfs_fill_vgapci, NULL,
  395                                     NULL, NULL, PFS_RD);
  396                                 cur_file->pn_data = (void*)dir;
  397                         }
  398                 }
  399         }
  400 
  401         error = device_get_children(dev, &children, &nchildren);
  402         if (error == 0) {
  403                 for (i = 0; i < nchildren; i++)
  404                         if (children[i])
  405                                 linsysfs_run_bus(children[i], dir, scsi,
  406                                     chardev, drm, new_path, prefix);
  407                 free(children, M_TEMP);
  408         }
  409         if (new_path != path)
  410                 free(new_path, M_TEMP);
  411         free(devname, M_TEMP);
  412 
  413         return (1);
  414 }
  415 
  416 /*
  417  * Filler function for sys/devices/system/cpu/online
  418  */
  419 static int
  420 linsysfs_cpuonline(PFS_FILL_ARGS)
  421 {
  422 
  423         sbuf_printf(sb, "%d-%d\n", CPU_FIRST(), mp_maxid);
  424         return (0);
  425 }
  426 
  427 /*
  428  * Filler function for sys/devices/system/cpu/cpuX/online
  429  */
  430 static int
  431 linsysfs_cpuxonline(PFS_FILL_ARGS)
  432 {
  433 
  434         sbuf_printf(sb, "1\n");
  435         return (0);
  436 }
  437 
  438 static void
  439 linsysfs_listcpus(struct pfs_node *dir)
  440 {
  441         struct pfs_node *cpu;
  442         char *name;
  443         int i, count, len;
  444 
  445         len = 1;
  446         count = mp_maxcpus;
  447         while (count > 10) {
  448                 count /= 10;
  449                 len++;
  450         }
  451         len += sizeof("cpu");
  452         name = malloc(len, M_TEMP, M_WAITOK);
  453 
  454         for (i = 0; i < mp_ncpus; ++i) {
  455                 /* /sys/devices/system/cpu/cpuX */
  456                 sprintf(name, "cpu%d", i);
  457                 cpu = pfs_create_dir(dir, name, NULL, NULL, NULL, 0);
  458 
  459                 pfs_create_file(cpu, "online", &linsysfs_cpuxonline,
  460                     NULL, NULL, NULL, PFS_RD);
  461         }
  462         free(name, M_TEMP);
  463 }
  464 
  465 /*
  466  * Constructor
  467  */
  468 static int
  469 linsysfs_init(PFS_INIT_ARGS)
  470 {
  471         struct pfs_node *root;
  472         struct pfs_node *class;
  473         struct pfs_node *dir, *sys, *cpu;
  474         struct pfs_node *drm;
  475         struct pfs_node *pci;
  476         struct pfs_node *scsi;
  477         struct pfs_node *devdir, *chardev;
  478         devclass_t devclass;
  479         device_t dev;
  480 
  481         TAILQ_INIT(&scsi_host_q);
  482 
  483         root = pi->pi_root;
  484 
  485         /* /sys/class/... */
  486         class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0);
  487         scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0);
  488         drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0);
  489 
  490         /* /sys/dev/... */
  491         devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0);
  492         chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0);
  493 
  494         /* /sys/devices/... */
  495         dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0);
  496         pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0);
  497 
  498         devclass = devclass_find("root");
  499         if (devclass == NULL) {
  500                 return (0);
  501         }
  502 
  503         dev = devclass_get_device(devclass, 0);
  504         linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000");
  505 
  506         /* /sys/devices/system */
  507         sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0);
  508 
  509         /* /sys/devices/system/cpu */
  510         cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0);
  511 
  512         pfs_create_file(cpu, "online", &linsysfs_cpuonline,
  513             NULL, NULL, NULL, PFS_RD);
  514 
  515         linsysfs_listcpus(cpu);
  516 
  517         return (0);
  518 }
  519 
  520 /*
  521  * Destructor
  522  */
  523 static int
  524 linsysfs_uninit(PFS_INIT_ARGS)
  525 {
  526         struct scsi_host_queue *scsi_host, *scsi_host_tmp;
  527 
  528         TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next,
  529             scsi_host_tmp) {
  530                 TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next);
  531                 free(scsi_host->path, M_TEMP);
  532                 free(scsi_host, M_TEMP);
  533         }
  534 
  535         return (0);
  536 }
  537 
  538 PSEUDOFS(linsysfs, 1, PR_ALLOW_MOUNT_LINSYSFS);
  539 #if defined(__amd64__)
  540 MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1);
  541 #else
  542 MODULE_DEPEND(linsysfs, linux, 1, 1, 1);
  543 #endif

Cache object: d0c3d8b0ac87039bdad59a3dcf3eae6c


[ 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.