⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		for (i = 0; i < cfg->nummaps; i++) {			pcimap *m = &cfg->map[i];			printf("\tmap[%d]: type %x, range %2d, base %08x, size %2d\n",			       i, m->type, m->ln2range, m->base, m->ln2size);		}	}	pci_drvattach(dinfo); /* XXX currently defined in pci_compat.c */}/* scan one PCI bus for devices */static intpci_probebus(int bus){	pcicfgregs probe;	int bushigh = bus;#ifdef SIMOS#undef PCI_SLOTMAX#define PCI_SLOTMAX 0#endif	bzero(&probe, sizeof probe);	/* XXX KDM */	/* probe.parent = pci_bridgeto(bus); */	probe.bus = bus;	for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {		int pcifunchigh = 0;		for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) {			struct pci_devinfo *dinfo = pci_readcfg(&probe);			if (dinfo != NULL) {				if (dinfo->cfg.mfdev)					pcifunchigh = 7;				/*				 * XXX: Temporarily move pci_addcfg() up before				 * the use of cfg->subordinatebus. This is 				 * necessary, since pci_addcfg() calls the 				 * device's probe(), which may read the bus#				 * from some device dependent register of				 * some host to PCI bridges. The probe will 				 * eventually be moved to pci_readcfg(), and 				 * pci_addcfg() will then be moved back down				 * below the conditional statement ...				 */				pci_addcfg(dinfo);				if (bushigh < dinfo->cfg.subordinatebus)					bushigh = dinfo->cfg.subordinatebus;				if (bushigh < dinfo->cfg.secondarybus)					bushigh = dinfo->cfg.secondarybus;				/* XXX KDM */				/* cfg = NULL; we don't own this anymore ... */			}		}	}	return (bushigh);}/* scan a PCI bus tree reached through one PCI attachment point */intpci_probe(pciattach *parent){	int bushigh;	int bus = 0;	STAILQ_INIT(&pci_devq);	bushigh = pci_bushigh();	while (bus <= bushigh) {		int newbushigh;		printf("Probing for devices on PCI bus %d:\n", bus);		newbushigh = pci_probebus(bus);		if (bushigh < newbushigh)			bushigh = newbushigh;		bus++;	}	return (bushigh);}/* * This is the user interface to PCI configuration space. */  static intpci_open(dev_t dev, int oflags, int devtype, struct proc *p){	if ((oflags & FWRITE) && securelevel > 0) {		return EPERM;	}	return 0;}static intpci_close(dev_t dev, int flag, int devtype, struct proc *p){	return 0;}/* * Match a single pci_conf structure against an array of pci_match_conf * structures.  The first argument, 'matches', is an array of num_matches * pci_match_conf structures.  match_buf is a pointer to the pci_conf * structure that will be compared to every entry in the matches array. * This function returns 1 on failure, 0 on success. */static intpci_conf_match(struct pci_match_conf *matches, int num_matches, 	       struct pci_conf *match_buf){	int i;	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))		return(1);	for (i = 0; i < num_matches; i++) {		/*		 * I'm not sure why someone would do this...but...		 */		if (matches[i].flags == PCI_GETCONF_NO_MATCH)			continue;		/*		 * Look at each of the match flags.  If it's set, do the		 * comparison.  If the comparison fails, we don't have a		 * match, go on to the next item if there is one.		 */		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))			continue;		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))			continue;		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))			continue;		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 		 && (match_buf->pc_vendor != matches[i].pc_vendor))			continue;		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)		 && (match_buf->pc_device != matches[i].pc_device))			continue;		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)		 && (match_buf->pc_class != matches[i].pc_class))			continue;		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)		 && (match_buf->pd_unit != matches[i].pd_unit))			continue;		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)		 && (strncmp(matches[i].pd_name, match_buf->pd_name,			     sizeof(match_buf->pd_name)) != 0))			continue;		return(0);	}	return(1);}static intpci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p){	struct pci_io *io;	int error;	if (!(flag & FWRITE))		return EPERM;	switch(cmd) {	case PCIOCGETCONF:		{		struct pci_devinfo *dinfo;		struct pci_conf_io *cio;		struct devlist *devlist_head;		struct pci_match_conf *pattern_buf;		int num_patterns;		size_t iolen;		int ionum, i;		cio = (struct pci_conf_io *)data;		num_patterns = 0;		dinfo = NULL;		/*		 * Hopefully the user won't pass in a null pointer, but it		 * can't hurt to check.		 */		if (cio == NULL) {			error = EINVAL;			break;		}		/*		 * If the user specified an offset into the device list,		 * but the list has changed since they last called this		 * ioctl, tell them that the list has changed.  They will		 * have to get the list from the beginning.		 */		if ((cio->offset != 0)		 && (cio->generation != pci_generation)){			cio->num_matches = 0;				cio->status = PCI_GETCONF_LIST_CHANGED;			error = 0;			break;		}		/*		 * Check to see whether the user has asked for an offset		 * past the end of our list.		 */		if (cio->offset >= pci_numdevs) {			cio->num_matches = 0;			cio->status = PCI_GETCONF_LAST_DEVICE;			error = 0;			break;		}		/* get the head of the device queue */		devlist_head = &pci_devq;		/*		 * Determine how much room we have for pci_conf structures.		 * Round the user's buffer size down to the nearest		 * multiple of sizeof(struct pci_conf) in case the user		 * didn't specify a multiple of that size.		 */		iolen = min(cio->match_buf_len - 			    (cio->match_buf_len % sizeof(struct pci_conf)),			    pci_numdevs * sizeof(struct pci_conf));		/*		 * Since we know that iolen is a multiple of the size of		 * the pciconf union, it's okay to do this.		 */		ionum = iolen / sizeof(struct pci_conf);		/*		 * If this test is true, the user wants the pci_conf		 * structures returned to match the supplied entries.		 */		if ((cio->num_patterns > 0)		 && (cio->pat_buf_len > 0)) {			/*			 * pat_buf_len needs to be:			 * num_patterns * sizeof(struct pci_match_conf)			 * While it is certainly possible the user just			 * allocated a large buffer, but set the number of			 * matches correctly, it is far more likely that			 * their kernel doesn't match the userland utility			 * they're using.  It's also possible that the user			 * forgot to initialize some variables.  Yes, this			 * may be overly picky, but I hazard to guess that			 * it's far more likely to just catch folks that			 * updated their kernel but not their userland.			 */			if ((cio->num_patterns *			    sizeof(struct pci_match_conf)) != cio->pat_buf_len){				/* The user made a mistake, return an error*/				cio->status = PCI_GETCONF_ERROR;				printf("pci_ioctl: pat_buf_len %d != "				       "num_patterns (%d) * sizeof(struct "				       "pci_match_conf) (%d)\npci_ioctl: "				       "pat_buf_len should be = %d\n",				       cio->pat_buf_len, cio->num_patterns,				       sizeof(struct pci_match_conf),				       sizeof(struct pci_match_conf) * 				       cio->num_patterns);				printf("pci_ioctl: do your headers match your "				       "kernel?\n");				cio->num_matches = 0;				error = EINVAL;				break;			}			/*			 * Check the user's buffer to make sure it's readable.			 */			if ((error = useracc((caddr_t)cio->patterns,			                     cio->pat_buf_len, B_READ)) != 1){				printf("pci_ioctl: pattern buffer %p, "				       "length %u isn't user accessible for"				       " READ\n", cio->patterns,				       cio->pat_buf_len);				error = EACCES;				break;			}			/*			 * Allocate a buffer to hold the patterns.			 */			pattern_buf = malloc(cio->pat_buf_len, M_TEMP,					     M_WAITOK);			error = copyin(cio->patterns, pattern_buf,				       cio->pat_buf_len);			if (error != 0)				break;			num_patterns = cio->num_patterns;		} else if ((cio->num_patterns > 0)			|| (cio->pat_buf_len > 0)) {			/*			 * The user made a mistake, spit out an error.			 */			cio->status = PCI_GETCONF_ERROR;			cio->num_matches = 0;			printf("pci_ioctl: invalid GETCONF arguments\n");			error = EINVAL;			break;		} else			pattern_buf = NULL;		/*		 * Make sure we can write to the match buffer.		 */		if ((error = useracc((caddr_t)cio->matches, cio->match_buf_len,				     B_WRITE)) != 1) {			printf("pci_ioctl: match buffer %p, length %u "			       "isn't user accessible for WRITE\n",			       cio->matches, cio->match_buf_len);			error = EACCES;			break;		}		/*		 * Go through the list of devices and copy out the devices		 * that match the user's criteria.		 */		for (cio->num_matches = 0, error = 0, i = 0,		     dinfo = STAILQ_FIRST(devlist_head);		     (dinfo != NULL) && (cio->num_matches < ionum)		     && (error == 0) && (i < pci_numdevs);		     dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {			if (i < cio->offset)				continue;			if ((pattern_buf == NULL) ||			    (pci_conf_match(pattern_buf, num_patterns,					    &dinfo->conf) == 0)) {				/*				 * If we've filled up the user's buffer,				 * break out at this point.  Since we've				 * got a match here, we'll pick right back				 * up at the matching entry.  We can also				 * tell the user that there are more matches				 * left.				 */				if (cio->num_matches >= ionum)					break;				error = copyout(&dinfo->conf,					        &cio->matches[cio->num_matches],						sizeof(struct pci_conf));				cio->num_matches++;			}		}		/*		 * Set the pointer into the list, so if the user is getting		 * n records at a time, where n < pci_numdevs,		 */		cio->offset = i;		/*		 * Set the generation, the user will need this if they make		 * another ioctl call with offset != 0.		 */		cio->generation = pci_generation;				/*		 * If this is the last device, inform the user so he won't		 * bother asking for more devices.  If dinfo isn't NULL, we		 * know that there are more matches in the list because of		 * the way the traversal is done.		 */		if (dinfo == NULL)			cio->status = PCI_GETCONF_LAST_DEVICE;		else			cio->status = PCI_GETCONF_MORE_DEVS;		if (pattern_buf != NULL)			free(pattern_buf, M_TEMP);		break;		}	case PCIOCREAD:		io = (struct pci_io *)data;		switch(io->pi_width) {			pcicfgregs probe;		case 4:		case 2:		case 1:			probe.bus = io->pi_sel.pc_bus;			probe.slot = io->pi_sel.pc_dev;			probe.func = io->pi_sel.pc_func;			io->pi_data = pci_cfgread(&probe, 						  io->pi_reg, io->pi_width);			error = 0;			break;		default:			error = ENODEV;			break;		}		break;	case PCIOCWRITE:		io = (struct pci_io *)data;		switch(io->pi_width) {			pcicfgregs probe;		case 4:		case 2:		case 1:			probe.bus = io->pi_sel.pc_bus;			probe.slot = io->pi_sel.pc_dev;			probe.func = io->pi_sel.pc_func;			pci_cfgwrite(&probe, 				    io->pi_reg, io->pi_data, io->pi_width);			error = 0;			break;		default:			error = ENODEV;			break;		}		break;	default:		error = ENOTTY;		break;	}	return (error);}#define	PCI_CDEV	78static struct cdevsw pcicdev = {	pci_open, pci_close, noread, nowrite, pci_ioctl, nostop, noreset,	nodevtotty, seltrue, nommap, nostrategy, "pci", 0, PCI_CDEV};#ifdef DEVFSstatic void *pci_devfs_token;#endifstatic voidpci_cdevinit(void *dummy){	dev_t dev;	dev = makedev(PCI_CDEV, 0);	cdevsw_add(&dev, &pcicdev, NULL);#ifdef	DEVFS	pci_devfs_token = devfs_add_devswf(&pcicdev, 0, DV_CHR,					   UID_ROOT, GID_WHEEL, 0644, "pci");#endif}SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL);#endif /* NPCI > 0 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -