xref: /freebsd-src/sys/compat/linsysfs/linsysfs.c (revision 88362a00863a1c8369fab1cf63ad0e673403f7d0)
132397ce0SDoug Ambrisko /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
37f2d13d6SPedro F. Giffuni  *
432397ce0SDoug Ambrisko  * Copyright (c) 2006 IronPort Systems
532397ce0SDoug Ambrisko  * All rights reserved.
632397ce0SDoug Ambrisko  *
732397ce0SDoug Ambrisko  * Redistribution and use in source and binary forms, with or without
832397ce0SDoug Ambrisko  * modification, are permitted provided that the following conditions
932397ce0SDoug Ambrisko  * are met:
1032397ce0SDoug Ambrisko  * 1. Redistributions of source code must retain the above copyright
1132397ce0SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer.
1232397ce0SDoug Ambrisko  * 2. Redistributions in binary form must reproduce the above copyright
1332397ce0SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer in the
1432397ce0SDoug Ambrisko  *    documentation and/or other materials provided with the distribution.
1532397ce0SDoug Ambrisko  *
1632397ce0SDoug Ambrisko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1732397ce0SDoug Ambrisko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1832397ce0SDoug Ambrisko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1932397ce0SDoug Ambrisko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2032397ce0SDoug Ambrisko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2132397ce0SDoug Ambrisko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2232397ce0SDoug Ambrisko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2332397ce0SDoug Ambrisko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2432397ce0SDoug Ambrisko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2532397ce0SDoug Ambrisko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2632397ce0SDoug Ambrisko  * SUCH DAMAGE.
2732397ce0SDoug Ambrisko  */
2832397ce0SDoug Ambrisko 
2932397ce0SDoug Ambrisko #include <sys/param.h>
30eedc7fd9SGleb Smirnoff #include <sys/systm.h>
314e2f69f1SDmitry Chagin #include <sys/ctype.h>
3232397ce0SDoug Ambrisko #include <sys/kernel.h>
3332397ce0SDoug Ambrisko #include <sys/malloc.h>
3432397ce0SDoug Ambrisko #include <sys/mount.h>
3532397ce0SDoug Ambrisko #include <sys/sbuf.h>
3632397ce0SDoug Ambrisko #include <sys/smp.h>
3732397ce0SDoug Ambrisko #include <sys/bus.h>
3832397ce0SDoug Ambrisko #include <sys/pciio.h>
3932397ce0SDoug Ambrisko 
4032397ce0SDoug Ambrisko #include <dev/pci/pcivar.h>
4132397ce0SDoug Ambrisko #include <dev/pci/pcireg.h>
4232397ce0SDoug Ambrisko 
4332397ce0SDoug Ambrisko #include <compat/linux/linux_util.h>
4432397ce0SDoug Ambrisko #include <fs/pseudofs/pseudofs.h>
4532397ce0SDoug Ambrisko 
467ae0972cSDmitry Chagin #include <compat/linsysfs/linsysfs.h>
477ae0972cSDmitry Chagin 
487ae0972cSDmitry Chagin MALLOC_DEFINE(M_LINSYSFS, "linsysfs", "Linsysfs structures");
497ae0972cSDmitry Chagin 
5032397ce0SDoug Ambrisko struct scsi_host_queue {
5132397ce0SDoug Ambrisko 	TAILQ_ENTRY(scsi_host_queue) scsi_host_next;
5232397ce0SDoug Ambrisko 	char *path;
5332397ce0SDoug Ambrisko 	char *name;
5432397ce0SDoug Ambrisko };
5532397ce0SDoug Ambrisko 
5632397ce0SDoug Ambrisko TAILQ_HEAD(,scsi_host_queue) scsi_host_q;
5732397ce0SDoug Ambrisko 
5832397ce0SDoug Ambrisko static int host_number = 0;
5932397ce0SDoug Ambrisko 
6032397ce0SDoug Ambrisko static int
atoi(const char * str)6132397ce0SDoug Ambrisko atoi(const char *str)
6232397ce0SDoug Ambrisko {
6332397ce0SDoug Ambrisko 	return (int)strtol(str, (char **)NULL, 10);
6432397ce0SDoug Ambrisko }
6532397ce0SDoug Ambrisko 
6632397ce0SDoug Ambrisko /*
6732397ce0SDoug Ambrisko  * Filler function for proc_name
6832397ce0SDoug Ambrisko  */
6932397ce0SDoug Ambrisko static int
linsysfs_scsiname(PFS_FILL_ARGS)7032397ce0SDoug Ambrisko linsysfs_scsiname(PFS_FILL_ARGS)
7132397ce0SDoug Ambrisko {
7232397ce0SDoug Ambrisko 	struct scsi_host_queue *scsi_host;
7332397ce0SDoug Ambrisko 	int index;
7432397ce0SDoug Ambrisko 
7532397ce0SDoug Ambrisko 	if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
7632397ce0SDoug Ambrisko 		index = atoi(&pn->pn_parent->pn_name[4]);
7732397ce0SDoug Ambrisko 	} else {
7832397ce0SDoug Ambrisko 		sbuf_printf(sb, "unknown\n");
7932397ce0SDoug Ambrisko 		return (0);
8032397ce0SDoug Ambrisko 	}
8132397ce0SDoug Ambrisko 	TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
8232397ce0SDoug Ambrisko 		if (index-- == 0) {
8332397ce0SDoug Ambrisko 			sbuf_printf(sb, "%s\n", scsi_host->name);
8432397ce0SDoug Ambrisko 			return (0);
8532397ce0SDoug Ambrisko 		}
8632397ce0SDoug Ambrisko 	}
8732397ce0SDoug Ambrisko 	sbuf_printf(sb, "unknown\n");
8832397ce0SDoug Ambrisko 	return (0);
8932397ce0SDoug Ambrisko }
9032397ce0SDoug Ambrisko 
9132397ce0SDoug Ambrisko /*
9232397ce0SDoug Ambrisko  * Filler function for device sym-link
9332397ce0SDoug Ambrisko  */
9432397ce0SDoug Ambrisko static int
linsysfs_link_scsi_host(PFS_FILL_ARGS)9532397ce0SDoug Ambrisko linsysfs_link_scsi_host(PFS_FILL_ARGS)
9632397ce0SDoug Ambrisko {
9732397ce0SDoug Ambrisko 	struct scsi_host_queue *scsi_host;
9832397ce0SDoug Ambrisko 	int index;
9932397ce0SDoug Ambrisko 
10032397ce0SDoug Ambrisko 	if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
10132397ce0SDoug Ambrisko 		index = atoi(&pn->pn_parent->pn_name[4]);
10232397ce0SDoug Ambrisko 	} else {
10332397ce0SDoug Ambrisko 		sbuf_printf(sb, "unknown\n");
10432397ce0SDoug Ambrisko 		return (0);
10532397ce0SDoug Ambrisko 	}
10632397ce0SDoug Ambrisko 	TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
10732397ce0SDoug Ambrisko 		if (index-- == 0) {
10832397ce0SDoug Ambrisko 			sbuf_printf(sb, "../../../devices%s", scsi_host->path);
10932397ce0SDoug Ambrisko 			return(0);
11032397ce0SDoug Ambrisko 		}
11132397ce0SDoug Ambrisko 	}
11232397ce0SDoug Ambrisko 	sbuf_printf(sb, "unknown\n");
11332397ce0SDoug Ambrisko 	return (0);
11432397ce0SDoug Ambrisko }
11532397ce0SDoug Ambrisko 
11632397ce0SDoug Ambrisko static int
linsysfs_fill_data(PFS_FILL_ARGS)1172d347b2eSConrad Meyer linsysfs_fill_data(PFS_FILL_ARGS)
1182d347b2eSConrad Meyer {
1192e6418c0SRyan Libby 	sbuf_printf(sb, "%s", (char *)pn->pn_data);
1202d347b2eSConrad Meyer 	return (0);
1212d347b2eSConrad Meyer }
1222d347b2eSConrad Meyer 
1232d347b2eSConrad Meyer static int
linsysfs_fill_vendor(PFS_FILL_ARGS)1242d347b2eSConrad Meyer linsysfs_fill_vendor(PFS_FILL_ARGS)
1252d347b2eSConrad Meyer {
1262d347b2eSConrad Meyer 	sbuf_printf(sb, "0x%04x\n", pci_get_vendor((device_t)pn->pn_data));
1272d347b2eSConrad Meyer 	return (0);
1282d347b2eSConrad Meyer }
1292d347b2eSConrad Meyer 
1302d347b2eSConrad Meyer static int
linsysfs_fill_device(PFS_FILL_ARGS)1312d347b2eSConrad Meyer linsysfs_fill_device(PFS_FILL_ARGS)
1322d347b2eSConrad Meyer {
1332d347b2eSConrad Meyer 	sbuf_printf(sb, "0x%04x\n", pci_get_device((device_t)pn->pn_data));
1342d347b2eSConrad Meyer 	return (0);
1352d347b2eSConrad Meyer }
1362d347b2eSConrad Meyer 
1372d347b2eSConrad Meyer static int
linsysfs_fill_subvendor(PFS_FILL_ARGS)1382d347b2eSConrad Meyer linsysfs_fill_subvendor(PFS_FILL_ARGS)
1392d347b2eSConrad Meyer {
1402d347b2eSConrad Meyer 	sbuf_printf(sb, "0x%04x\n", pci_get_subvendor((device_t)pn->pn_data));
1412d347b2eSConrad Meyer 	return (0);
1422d347b2eSConrad Meyer }
1432d347b2eSConrad Meyer 
1442d347b2eSConrad Meyer static int
linsysfs_fill_subdevice(PFS_FILL_ARGS)1452d347b2eSConrad Meyer linsysfs_fill_subdevice(PFS_FILL_ARGS)
1462d347b2eSConrad Meyer {
1472d347b2eSConrad Meyer 	sbuf_printf(sb, "0x%04x\n", pci_get_subdevice((device_t)pn->pn_data));
1482d347b2eSConrad Meyer 	return (0);
1492d347b2eSConrad Meyer }
1502d347b2eSConrad Meyer 
1512d347b2eSConrad Meyer static int
linsysfs_fill_revid(PFS_FILL_ARGS)1522d347b2eSConrad Meyer linsysfs_fill_revid(PFS_FILL_ARGS)
1532d347b2eSConrad Meyer {
1542d347b2eSConrad Meyer 	sbuf_printf(sb, "0x%x\n", pci_get_revid((device_t)pn->pn_data));
1552d347b2eSConrad Meyer 	return (0);
1562d347b2eSConrad Meyer }
1572d347b2eSConrad Meyer 
15803cea61bSTijl Coosemans static int
linsysfs_fill_config(PFS_FILL_ARGS)15903cea61bSTijl Coosemans linsysfs_fill_config(PFS_FILL_ARGS)
16003cea61bSTijl Coosemans {
16103cea61bSTijl Coosemans 	uint8_t config[48];
16203cea61bSTijl Coosemans 	device_t dev;
16303cea61bSTijl Coosemans 	uint32_t reg;
16403cea61bSTijl Coosemans 
16503cea61bSTijl Coosemans 	dev = (device_t)pn->pn_data;
16603cea61bSTijl Coosemans 	bzero(config, sizeof(config));
16703cea61bSTijl Coosemans 	reg = pci_get_vendor(dev);
16803cea61bSTijl Coosemans 	config[0] = reg;
16903cea61bSTijl Coosemans 	config[1] = reg >> 8;
17003cea61bSTijl Coosemans 	reg = pci_get_device(dev);
17103cea61bSTijl Coosemans 	config[2] = reg;
17203cea61bSTijl Coosemans 	config[3] = reg >> 8;
17303cea61bSTijl Coosemans 	reg = pci_get_revid(dev);
17403cea61bSTijl Coosemans 	config[8] = reg;
17503cea61bSTijl Coosemans 	reg = pci_get_subvendor(dev);
17603cea61bSTijl Coosemans 	config[44] = reg;
17703cea61bSTijl Coosemans 	config[45] = reg >> 8;
17803cea61bSTijl Coosemans 	reg = pci_get_subdevice(dev);
17903cea61bSTijl Coosemans 	config[46] = reg;
18003cea61bSTijl Coosemans 	config[47] = reg >> 8;
18103cea61bSTijl Coosemans 	sbuf_bcat(sb, config, sizeof(config));
18203cea61bSTijl Coosemans 	return (0);
18303cea61bSTijl Coosemans }
18403cea61bSTijl Coosemans 
1852d347b2eSConrad Meyer /*
1862d347b2eSConrad Meyer  * Filler function for PCI uevent file
1872d347b2eSConrad Meyer  */
1882d347b2eSConrad Meyer static int
linsysfs_fill_uevent_pci(PFS_FILL_ARGS)1892d347b2eSConrad Meyer linsysfs_fill_uevent_pci(PFS_FILL_ARGS)
1902d347b2eSConrad Meyer {
1912d347b2eSConrad Meyer 	device_t dev;
1922d347b2eSConrad Meyer 
1932d347b2eSConrad Meyer 	dev = (device_t)pn->pn_data;
1942d347b2eSConrad Meyer 	sbuf_printf(sb, "DRIVER=%s\nPCI_CLASS=%X\nPCI_ID=%04X:%04X\n"
1952d347b2eSConrad Meyer 	    "PCI_SUBSYS_ID=%04X:%04X\nPCI_SLOT_NAME=%04d:%02x:%02x.%x\n",
1962d347b2eSConrad Meyer 	    linux_driver_get_name_dev(dev), pci_get_class(dev),
1972d347b2eSConrad Meyer 	    pci_get_vendor(dev), pci_get_device(dev), pci_get_subvendor(dev),
1982d347b2eSConrad Meyer 	    pci_get_subdevice(dev), pci_get_domain(dev), pci_get_bus(dev),
1992d347b2eSConrad Meyer 	    pci_get_slot(dev), pci_get_function(dev));
2002d347b2eSConrad Meyer 	return (0);
2012d347b2eSConrad Meyer }
2022d347b2eSConrad Meyer 
2032d347b2eSConrad Meyer /*
2042d347b2eSConrad Meyer  * Filler function for drm uevent file
2052d347b2eSConrad Meyer  */
2062d347b2eSConrad Meyer static int
linsysfs_fill_uevent_drm(PFS_FILL_ARGS)2072d347b2eSConrad Meyer linsysfs_fill_uevent_drm(PFS_FILL_ARGS)
2082d347b2eSConrad Meyer {
2092d347b2eSConrad Meyer 	device_t dev;
2102d347b2eSConrad Meyer 	int unit;
2112d347b2eSConrad Meyer 
2122d347b2eSConrad Meyer 	dev = (device_t)pn->pn_data;
2132d347b2eSConrad Meyer 	unit = device_get_unit(dev);
2142d347b2eSConrad Meyer 	sbuf_printf(sb,
215df4c9752STijl Coosemans 	    "MAJOR=226\nMINOR=%d\nDEVNAME=dri/card%d\nDEVTYPE=dri_minor\n",
216df4c9752STijl Coosemans 	    unit, unit);
2172d347b2eSConrad Meyer 	return (0);
2182d347b2eSConrad Meyer }
2192d347b2eSConrad Meyer 
2202d347b2eSConrad Meyer static char *
get_full_pfs_path(struct pfs_node * cur)2212d347b2eSConrad Meyer get_full_pfs_path(struct pfs_node *cur)
2222d347b2eSConrad Meyer {
2232d347b2eSConrad Meyer 	char *temp, *path;
2242d347b2eSConrad Meyer 
2252d347b2eSConrad Meyer 	temp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
2262d347b2eSConrad Meyer 	path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
2272d347b2eSConrad Meyer 	path[0] = '\0';
2282d347b2eSConrad Meyer 
2292d347b2eSConrad Meyer 	do {
2302d347b2eSConrad Meyer 		snprintf(temp, MAXPATHLEN, "%s/%s", cur->pn_name, path);
2312d347b2eSConrad Meyer 		strlcpy(path, temp, MAXPATHLEN);
2322d347b2eSConrad Meyer 		cur = cur->pn_parent;
2332d347b2eSConrad Meyer 	} while (cur->pn_parent != NULL);
2342d347b2eSConrad Meyer 
2352d347b2eSConrad Meyer 	path[strlen(path) - 1] = '\0'; /* remove extra slash */
2362d347b2eSConrad Meyer 	free(temp, M_TEMP);
2372d347b2eSConrad Meyer 	return (path);
2382d347b2eSConrad Meyer }
2392d347b2eSConrad Meyer 
2402d347b2eSConrad Meyer /*
2412d347b2eSConrad Meyer  * Filler function for symlink from drm char device to PCI device
2422d347b2eSConrad Meyer  */
2432d347b2eSConrad Meyer static int
linsysfs_fill_vgapci(PFS_FILL_ARGS)2442d347b2eSConrad Meyer linsysfs_fill_vgapci(PFS_FILL_ARGS)
2452d347b2eSConrad Meyer {
2462d347b2eSConrad Meyer 	char *path;
2472d347b2eSConrad Meyer 
2482d347b2eSConrad Meyer 	path = get_full_pfs_path((struct pfs_node*)pn->pn_data);
2492d347b2eSConrad Meyer 	sbuf_printf(sb, "../../../%s", path);
2502d347b2eSConrad Meyer 	free(path, M_TEMP);
2512d347b2eSConrad Meyer 	return (0);
2522d347b2eSConrad Meyer }
2532d347b2eSConrad Meyer 
254971b5f76SWarner Losh #undef PCI_DEV
2552d347b2eSConrad Meyer #define PCI_DEV "pci"
2562d347b2eSConrad Meyer #define DRMN_DEV "drmn"
2572d347b2eSConrad Meyer static int
linsysfs_run_bus(device_t dev,struct pfs_node * dir,struct pfs_node * scsi,struct pfs_node * chardev,struct pfs_node * drm,char * path,char * prefix)25803cea61bSTijl Coosemans linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
25903cea61bSTijl Coosemans     struct pfs_node *chardev, struct pfs_node *drm, char *path, char *prefix)
26032397ce0SDoug Ambrisko {
26132397ce0SDoug Ambrisko 	struct scsi_host_queue *scsi_host;
26203cea61bSTijl Coosemans 	struct pfs_node *sub_dir, *cur_file;
2634d367f25SConrad Meyer 	int i, nchildren, error;
26432397ce0SDoug Ambrisko 	device_t *children, parent;
26532397ce0SDoug Ambrisko 	devclass_t devclass;
26632397ce0SDoug Ambrisko 	const char *name = NULL;
26732397ce0SDoug Ambrisko 	struct pci_devinfo *dinfo;
26803cea61bSTijl Coosemans 	char *device, *host, *new_path, *devname;
2692d347b2eSConrad Meyer 
2702d347b2eSConrad Meyer 	new_path = path;
27103cea61bSTijl Coosemans 	devname = malloc(16, M_TEMP, M_WAITOK);
27232397ce0SDoug Ambrisko 
27332397ce0SDoug Ambrisko 	parent = device_get_parent(dev);
27432397ce0SDoug Ambrisko 	if (parent) {
27532397ce0SDoug Ambrisko 		devclass = device_get_devclass(parent);
27632397ce0SDoug Ambrisko 		if (devclass != NULL)
27732397ce0SDoug Ambrisko 			name = devclass_get_name(devclass);
27832397ce0SDoug Ambrisko 		if (name && strcmp(name, PCI_DEV) == 0) {
27932397ce0SDoug Ambrisko 			dinfo = device_get_ivars(dev);
28032397ce0SDoug Ambrisko 			if (dinfo) {
28132397ce0SDoug Ambrisko 				device = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
28232397ce0SDoug Ambrisko 				new_path = malloc(MAXPATHLEN, M_TEMP,
28332397ce0SDoug Ambrisko 				    M_WAITOK);
28432397ce0SDoug Ambrisko 				new_path[0] = '\000';
28532397ce0SDoug Ambrisko 				strcpy(new_path, path);
28632397ce0SDoug Ambrisko 				host = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
28732397ce0SDoug Ambrisko 				device[0] = '\000';
28832397ce0SDoug Ambrisko 				sprintf(device, "%s:%02x:%02x.%x",
28932397ce0SDoug Ambrisko 				    prefix,
29032397ce0SDoug Ambrisko 				    dinfo->cfg.bus,
29132397ce0SDoug Ambrisko 				    dinfo->cfg.slot,
29232397ce0SDoug Ambrisko 				    dinfo->cfg.func);
29332397ce0SDoug Ambrisko 				strcat(new_path, "/");
29432397ce0SDoug Ambrisko 				strcat(new_path, device);
29532397ce0SDoug Ambrisko 				dir = pfs_create_dir(dir, device,
296771709ebSDag-Erling Smørgrav 				    NULL, NULL, NULL, 0);
2972d347b2eSConrad Meyer 				cur_file = pfs_create_file(dir, "vendor",
2982d347b2eSConrad Meyer 				    &linsysfs_fill_vendor, NULL, NULL, NULL,
2992d347b2eSConrad Meyer 				    PFS_RD);
3002d347b2eSConrad Meyer 				cur_file->pn_data = (void*)dev;
3012d347b2eSConrad Meyer 				cur_file = pfs_create_file(dir, "device",
3022d347b2eSConrad Meyer 				    &linsysfs_fill_device, NULL, NULL, NULL,
3032d347b2eSConrad Meyer 				    PFS_RD);
3042d347b2eSConrad Meyer 				cur_file->pn_data = (void*)dev;
3052d347b2eSConrad Meyer 				cur_file = pfs_create_file(dir,
3062d347b2eSConrad Meyer 				    "subsystem_vendor",
3072d347b2eSConrad Meyer 				    &linsysfs_fill_subvendor, NULL, NULL, NULL,
3082d347b2eSConrad Meyer 				    PFS_RD);
3092d347b2eSConrad Meyer 				cur_file->pn_data = (void*)dev;
3102d347b2eSConrad Meyer 				cur_file = pfs_create_file(dir,
3112d347b2eSConrad Meyer 				    "subsystem_device",
3122d347b2eSConrad Meyer 				    &linsysfs_fill_subdevice, NULL, NULL, NULL,
3132d347b2eSConrad Meyer 				    PFS_RD);
3142d347b2eSConrad Meyer 				cur_file->pn_data = (void*)dev;
3152d347b2eSConrad Meyer 				cur_file = pfs_create_file(dir, "revision",
3162d347b2eSConrad Meyer 				    &linsysfs_fill_revid, NULL, NULL, NULL,
3172d347b2eSConrad Meyer 				    PFS_RD);
3182d347b2eSConrad Meyer 				cur_file->pn_data = (void*)dev;
31903cea61bSTijl Coosemans 				cur_file = pfs_create_file(dir, "config",
32003cea61bSTijl Coosemans 				    &linsysfs_fill_config, NULL, NULL, NULL,
32103cea61bSTijl Coosemans 				    PFS_RD);
32203cea61bSTijl Coosemans 				cur_file->pn_data = (void*)dev;
3232d347b2eSConrad Meyer 				cur_file = pfs_create_file(dir, "uevent",
3242d347b2eSConrad Meyer 				    &linsysfs_fill_uevent_pci, NULL, NULL,
3252d347b2eSConrad Meyer 				    NULL, PFS_RD);
3262d347b2eSConrad Meyer 				cur_file->pn_data = (void*)dev;
3272d347b2eSConrad Meyer 				cur_file = pfs_create_link(dir, "subsystem",
3282d347b2eSConrad Meyer 				    &linsysfs_fill_data, NULL, NULL, NULL, 0);
3292d347b2eSConrad Meyer 				/* libdrm just checks that the link ends in "/pci" */
3302d347b2eSConrad Meyer 				cur_file->pn_data = "/sys/bus/pci";
33132397ce0SDoug Ambrisko 
33232397ce0SDoug Ambrisko 				if (dinfo->cfg.baseclass == PCIC_STORAGE) {
33332397ce0SDoug Ambrisko 					/* DJA only make this if needed */
33432397ce0SDoug Ambrisko 					sprintf(host, "host%d", host_number++);
33532397ce0SDoug Ambrisko 					strcat(new_path, "/");
33632397ce0SDoug Ambrisko 					strcat(new_path, host);
33736b0a373SDag-Erling Smørgrav 					pfs_create_dir(dir, host,
33836b0a373SDag-Erling Smørgrav 					    NULL, NULL, NULL, 0);
33932397ce0SDoug Ambrisko 					scsi_host = malloc(sizeof(
34032397ce0SDoug Ambrisko 					    struct scsi_host_queue),
34132397ce0SDoug Ambrisko 					    M_DEVBUF, M_NOWAIT);
34232397ce0SDoug Ambrisko 					scsi_host->path = malloc(
34332397ce0SDoug Ambrisko 					    strlen(new_path) + 1,
34432397ce0SDoug Ambrisko 					    M_DEVBUF, M_NOWAIT);
34532397ce0SDoug Ambrisko 					scsi_host->path[0] = '\000';
34632397ce0SDoug Ambrisko 					bcopy(new_path, scsi_host->path,
34732397ce0SDoug Ambrisko 					    strlen(new_path) + 1);
34832397ce0SDoug Ambrisko 					scsi_host->name = "unknown";
34932397ce0SDoug Ambrisko 
35032397ce0SDoug Ambrisko 					sub_dir = pfs_create_dir(scsi, host,
351771709ebSDag-Erling Smørgrav 					    NULL, NULL, NULL, 0);
35232397ce0SDoug Ambrisko 					pfs_create_link(sub_dir, "device",
35332397ce0SDoug Ambrisko 					    &linsysfs_link_scsi_host,
354771709ebSDag-Erling Smørgrav 					    NULL, NULL, NULL, 0);
35532397ce0SDoug Ambrisko 					pfs_create_file(sub_dir, "proc_name",
35632397ce0SDoug Ambrisko 					    &linsysfs_scsiname,
357771709ebSDag-Erling Smørgrav 					    NULL, NULL, NULL, PFS_RD);
35832397ce0SDoug Ambrisko 					scsi_host->name
35932397ce0SDoug Ambrisko 					    = linux_driver_get_name_dev(dev);
36032397ce0SDoug Ambrisko 					TAILQ_INSERT_TAIL(&scsi_host_q,
36132397ce0SDoug Ambrisko 					    scsi_host, scsi_host_next);
36232397ce0SDoug Ambrisko 				}
36332397ce0SDoug Ambrisko 				free(device, M_TEMP);
36432397ce0SDoug Ambrisko 				free(host, M_TEMP);
36532397ce0SDoug Ambrisko 			}
36632397ce0SDoug Ambrisko 		}
3672d347b2eSConrad Meyer 
3682d347b2eSConrad Meyer 		devclass = device_get_devclass(dev);
3692d347b2eSConrad Meyer 		if (devclass != NULL)
3702d347b2eSConrad Meyer 			name = devclass_get_name(devclass);
3714d367f25SConrad Meyer 		else
3724d367f25SConrad Meyer 			name = NULL;
3732d347b2eSConrad Meyer 		if (name != NULL && strcmp(name, DRMN_DEV) == 0 &&
3742d347b2eSConrad Meyer 		    device_get_unit(dev) >= 0) {
3754d367f25SConrad Meyer 			dinfo = device_get_ivars(parent);
3764d367f25SConrad Meyer 			if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) {
37755258ab0STijl Coosemans 				pfs_create_dir(dir, "drm", NULL, NULL, NULL, 0);
37803cea61bSTijl Coosemans 				sprintf(devname, "226:%d",
3792d347b2eSConrad Meyer 				    device_get_unit(dev));
38003cea61bSTijl Coosemans 				sub_dir = pfs_create_dir(chardev,
38103cea61bSTijl Coosemans 				    devname, NULL, NULL, NULL, 0);
38203cea61bSTijl Coosemans 				cur_file = pfs_create_link(sub_dir,
3832d347b2eSConrad Meyer 				    "device", &linsysfs_fill_vgapci, NULL,
3842d347b2eSConrad Meyer 				    NULL, NULL, PFS_RD);
3852d347b2eSConrad Meyer 				cur_file->pn_data = (void*)dir;
38603cea61bSTijl Coosemans 				cur_file = pfs_create_file(sub_dir,
3872d347b2eSConrad Meyer 				    "uevent", &linsysfs_fill_uevent_drm, NULL,
3882d347b2eSConrad Meyer 				    NULL, NULL, PFS_RD);
3892d347b2eSConrad Meyer 				cur_file->pn_data = (void*)dev;
39003cea61bSTijl Coosemans 				sprintf(devname, "card%d",
39103cea61bSTijl Coosemans 				    device_get_unit(dev));
39203cea61bSTijl Coosemans 				sub_dir = pfs_create_dir(drm,
39303cea61bSTijl Coosemans 				    devname, NULL, NULL, NULL, 0);
39403cea61bSTijl Coosemans 				cur_file = pfs_create_link(sub_dir,
39503cea61bSTijl Coosemans 				    "device", &linsysfs_fill_vgapci, NULL,
39603cea61bSTijl Coosemans 				    NULL, NULL, PFS_RD);
39703cea61bSTijl Coosemans 				cur_file->pn_data = (void*)dir;
3982d347b2eSConrad Meyer 			}
3992d347b2eSConrad Meyer 		}
40032397ce0SDoug Ambrisko 	}
40132397ce0SDoug Ambrisko 
4024d367f25SConrad Meyer 	error = device_get_children(dev, &children, &nchildren);
4034d367f25SConrad Meyer 	if (error == 0) {
4044d367f25SConrad Meyer 		for (i = 0; i < nchildren; i++)
40532397ce0SDoug Ambrisko 			if (children[i])
4064d367f25SConrad Meyer 				linsysfs_run_bus(children[i], dir, scsi,
40703cea61bSTijl Coosemans 				    chardev, drm, new_path, prefix);
4084d367f25SConrad Meyer 		free(children, M_TEMP);
40932397ce0SDoug Ambrisko 	}
41032397ce0SDoug Ambrisko 	if (new_path != path)
41132397ce0SDoug Ambrisko 		free(new_path, M_TEMP);
41203cea61bSTijl Coosemans 	free(devname, M_TEMP);
41332397ce0SDoug Ambrisko 
41432397ce0SDoug Ambrisko 	return (1);
41532397ce0SDoug Ambrisko }
41632397ce0SDoug Ambrisko 
41732397ce0SDoug Ambrisko /*
41812f3888aSEdward Tomasz Napierala  * Filler function for sys/devices/system/cpu/{online,possible,present}
419039aba08SDmitry Chagin  */
420039aba08SDmitry Chagin static int
linsysfs_cpuonline(PFS_FILL_ARGS)421039aba08SDmitry Chagin linsysfs_cpuonline(PFS_FILL_ARGS)
422039aba08SDmitry Chagin {
423039aba08SDmitry Chagin 
424039aba08SDmitry Chagin 	sbuf_printf(sb, "%d-%d\n", CPU_FIRST(), mp_maxid);
425039aba08SDmitry Chagin 	return (0);
426039aba08SDmitry Chagin }
427039aba08SDmitry Chagin 
428039aba08SDmitry Chagin /*
429039aba08SDmitry Chagin  * Filler function for sys/devices/system/cpu/cpuX/online
430039aba08SDmitry Chagin  */
431039aba08SDmitry Chagin static int
linsysfs_cpuxonline(PFS_FILL_ARGS)432039aba08SDmitry Chagin linsysfs_cpuxonline(PFS_FILL_ARGS)
433039aba08SDmitry Chagin {
434039aba08SDmitry Chagin 
435039aba08SDmitry Chagin 	sbuf_printf(sb, "1\n");
436039aba08SDmitry Chagin 	return (0);
437039aba08SDmitry Chagin }
438039aba08SDmitry Chagin 
439039aba08SDmitry Chagin static void
linsysfs_listcpus(struct pfs_node * dir)440039aba08SDmitry Chagin linsysfs_listcpus(struct pfs_node *dir)
441039aba08SDmitry Chagin {
442039aba08SDmitry Chagin 	struct pfs_node *cpu;
443039aba08SDmitry Chagin 	char *name;
444039aba08SDmitry Chagin 	int i, count, len;
445039aba08SDmitry Chagin 
446039aba08SDmitry Chagin 	len = 1;
447039aba08SDmitry Chagin 	count = mp_maxcpus;
448039aba08SDmitry Chagin 	while (count > 10) {
449039aba08SDmitry Chagin 		count /= 10;
450039aba08SDmitry Chagin 		len++;
451039aba08SDmitry Chagin 	}
452039aba08SDmitry Chagin 	len += sizeof("cpu");
453039aba08SDmitry Chagin 	name = malloc(len, M_TEMP, M_WAITOK);
454039aba08SDmitry Chagin 
455039aba08SDmitry Chagin 	for (i = 0; i < mp_ncpus; ++i) {
456039aba08SDmitry Chagin 		/* /sys/devices/system/cpu/cpuX */
457039aba08SDmitry Chagin 		sprintf(name, "cpu%d", i);
458039aba08SDmitry Chagin 		cpu = pfs_create_dir(dir, name, NULL, NULL, NULL, 0);
459039aba08SDmitry Chagin 
460039aba08SDmitry Chagin 		pfs_create_file(cpu, "online", &linsysfs_cpuxonline,
461039aba08SDmitry Chagin 		    NULL, NULL, NULL, PFS_RD);
462039aba08SDmitry Chagin 	}
463039aba08SDmitry Chagin 	free(name, M_TEMP);
464039aba08SDmitry Chagin }
465039aba08SDmitry Chagin 
466039aba08SDmitry Chagin /*
46732397ce0SDoug Ambrisko  * Constructor
46832397ce0SDoug Ambrisko  */
46932397ce0SDoug Ambrisko static int
linsysfs_init(PFS_INIT_ARGS)47032397ce0SDoug Ambrisko linsysfs_init(PFS_INIT_ARGS)
47132397ce0SDoug Ambrisko {
47232397ce0SDoug Ambrisko 	struct pfs_node *root;
47303cea61bSTijl Coosemans 	struct pfs_node *class;
474039aba08SDmitry Chagin 	struct pfs_node *dir, *sys, *cpu;
47503cea61bSTijl Coosemans 	struct pfs_node *drm;
47632397ce0SDoug Ambrisko 	struct pfs_node *pci;
47732397ce0SDoug Ambrisko 	struct pfs_node *scsi;
4782d347b2eSConrad Meyer 	struct pfs_node *devdir, *chardev;
47946888dedSMark Johnston 	struct pfs_node *kernel;
48032397ce0SDoug Ambrisko 	devclass_t devclass;
48132397ce0SDoug Ambrisko 	device_t dev;
48232397ce0SDoug Ambrisko 
48332397ce0SDoug Ambrisko 	TAILQ_INIT(&scsi_host_q);
48432397ce0SDoug Ambrisko 
48532397ce0SDoug Ambrisko 	root = pi->pi_root;
48632397ce0SDoug Ambrisko 
487dc0119c2SEdward Tomasz Napierala 	/* /sys/bus/... */
488dc0119c2SEdward Tomasz Napierala 	dir = pfs_create_dir(root, "bus", NULL, NULL, NULL, 0);
489dc0119c2SEdward Tomasz Napierala 
49032397ce0SDoug Ambrisko 	/* /sys/class/... */
49103cea61bSTijl Coosemans 	class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0);
49203cea61bSTijl Coosemans 	scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0);
49303cea61bSTijl Coosemans 	drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0);
494bafe3b88SDmitry Chagin 	pfs_create_dir(class, "power_supply", NULL, NULL, NULL, 0);
49532397ce0SDoug Ambrisko 
4964e2f69f1SDmitry Chagin 	/* /sys/class/net/.. */
4974e2f69f1SDmitry Chagin 	net = pfs_create_dir(class, "net", NULL, NULL, NULL, 0);
4984e2f69f1SDmitry Chagin 
49903cea61bSTijl Coosemans 	/* /sys/dev/... */
5002d347b2eSConrad Meyer 	devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0);
5012d347b2eSConrad Meyer 	chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0);
5022d347b2eSConrad Meyer 
50303cea61bSTijl Coosemans 	/* /sys/devices/... */
50403cea61bSTijl Coosemans 	dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0);
50503cea61bSTijl Coosemans 	pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0);
50603cea61bSTijl Coosemans 
50732397ce0SDoug Ambrisko 	devclass = devclass_find("root");
50832397ce0SDoug Ambrisko 	if (devclass == NULL) {
50932397ce0SDoug Ambrisko 		return (0);
51032397ce0SDoug Ambrisko 	}
51132397ce0SDoug Ambrisko 
51232397ce0SDoug Ambrisko 	dev = devclass_get_device(devclass, 0);
51303cea61bSTijl Coosemans 	linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000");
514039aba08SDmitry Chagin 
515039aba08SDmitry Chagin 	/* /sys/devices/system */
516039aba08SDmitry Chagin 	sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0);
517039aba08SDmitry Chagin 
518039aba08SDmitry Chagin 	/* /sys/devices/system/cpu */
519039aba08SDmitry Chagin 	cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0);
520039aba08SDmitry Chagin 
521039aba08SDmitry Chagin 	pfs_create_file(cpu, "online", &linsysfs_cpuonline,
522039aba08SDmitry Chagin 	    NULL, NULL, NULL, PFS_RD);
52312f3888aSEdward Tomasz Napierala 	pfs_create_file(cpu, "possible", &linsysfs_cpuonline,
52412f3888aSEdward Tomasz Napierala 	    NULL, NULL, NULL, PFS_RD);
52512f3888aSEdward Tomasz Napierala 	pfs_create_file(cpu, "present", &linsysfs_cpuonline,
52612f3888aSEdward Tomasz Napierala 	    NULL, NULL, NULL, PFS_RD);
527039aba08SDmitry Chagin 
528039aba08SDmitry Chagin 	linsysfs_listcpus(cpu);
529039aba08SDmitry Chagin 
53046888dedSMark Johnston 	/* /sys/kernel */
53146888dedSMark Johnston 	kernel = pfs_create_dir(root, "kernel", NULL, NULL, NULL, 0);
53246888dedSMark Johnston 	/* /sys/kernel/debug, mountpoint for lindebugfs. */
533bafe3b88SDmitry Chagin 	pfs_create_dir(kernel, "debug", NULL, NULL, NULL, 0);
53446888dedSMark Johnston 
5357ae0972cSDmitry Chagin 	linsysfs_net_init();
5367ae0972cSDmitry Chagin 
53732397ce0SDoug Ambrisko 	return (0);
53832397ce0SDoug Ambrisko }
53932397ce0SDoug Ambrisko 
54032397ce0SDoug Ambrisko /*
54132397ce0SDoug Ambrisko  * Destructor
54232397ce0SDoug Ambrisko  */
54332397ce0SDoug Ambrisko static int
linsysfs_uninit(PFS_INIT_ARGS)54432397ce0SDoug Ambrisko linsysfs_uninit(PFS_INIT_ARGS)
54532397ce0SDoug Ambrisko {
5465ac73157SAlexander Leidinger 	struct scsi_host_queue *scsi_host, *scsi_host_tmp;
54732397ce0SDoug Ambrisko 
5485ac73157SAlexander Leidinger 	TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next,
5495ac73157SAlexander Leidinger 	    scsi_host_tmp) {
55032397ce0SDoug Ambrisko 		TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next);
55132397ce0SDoug Ambrisko 		free(scsi_host->path, M_TEMP);
55232397ce0SDoug Ambrisko 		free(scsi_host, M_TEMP);
55332397ce0SDoug Ambrisko 	}
55432397ce0SDoug Ambrisko 
5557ae0972cSDmitry Chagin 	linsysfs_net_uninit();
5567ae0972cSDmitry Chagin 
55732397ce0SDoug Ambrisko 	return (0);
55832397ce0SDoug Ambrisko }
55932397ce0SDoug Ambrisko 
5600e5c6bd4SJamie Gritton PSEUDOFS(linsysfs, 1, VFCF_JAIL);
561bbc82947SEd Maste #if defined(__aarch64__) || defined(__amd64__)
56267d39748SDmitry Chagin MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1);
56367d39748SDmitry Chagin #else
56432397ce0SDoug Ambrisko MODULE_DEPEND(linsysfs, linux, 1, 1, 1);
56567d39748SDmitry Chagin #endif
566