424 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			424 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a
 | |
|  * copy of this software and associated documentation files (the "Software"),
 | |
|  * to deal in the Software without restriction, including without limitation
 | |
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | |
|  * and/or sell copies of the Software, and to permit persons to whom the
 | |
|  * Software is furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | |
|  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
|  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
|  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | |
|  * OTHER DEALINGS IN THE SOFTWARE.
 | |
|  *
 | |
|  * Except as contained in this notice, the name of the copyright holder(s)
 | |
|  * and author(s) shall not be used in advertising or otherwise to promote
 | |
|  * the sale, use or other dealings in this Software without prior written
 | |
|  * authorization from the copyright holder(s) and author(s).
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * This file contains the interfaces to the bus-specific code
 | |
|  */
 | |
| #ifdef HAVE_XORG_CONFIG_H
 | |
| #include <xorg-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <ctype.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| #include <X11/X.h>
 | |
| #include <pciaccess.h>
 | |
| #include "os.h"
 | |
| #include "Pci.h"
 | |
| #include "xf86.h"
 | |
| #include "xf86Priv.h"
 | |
| 
 | |
| /* Bus-specific headers */
 | |
| #include "xf86Bus.h"
 | |
| 
 | |
| #define XF86_OS_PRIVS
 | |
| #include "xf86_OSproc.h"
 | |
| 
 | |
| 
 | |
| /* Bus-specific globals */
 | |
| Bool pciSlotClaimed = FALSE;
 | |
| 
 | |
| #define PCIINFOCLASSES(c) \
 | |
|     ( (((c) & 0x00ff0000) == (PCI_CLASS_PREHISTORIC << 16)) \
 | |
|       || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \
 | |
|       || ((((c) & 0x00ffff00) \
 | |
| 	   == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) \
 | |
|       || ((((c) & 0x00ffff00) \
 | |
| 	   == ((PCI_CLASS_PROCESSOR << 16) | (PCI_SUBCLASS_PROCESSOR_COPROC << 8)))) )
 | |
| 
 | |
| /*
 | |
|  * PCI classes that have messages printed always.  The others are only
 | |
|  * have a message printed when the vendor/dev IDs are recognised.
 | |
|  */
 | |
| #define PCIALWAYSPRINTCLASSES(c) \
 | |
|     ( (((c) & 0x00ffff00) \
 | |
|        == ((PCI_CLASS_PREHISTORIC << 16) | (PCI_SUBCLASS_PREHISTORIC_VGA << 8))) \
 | |
|       || (((c) & 0x00ff0000) == (PCI_CLASS_DISPLAY << 16)) \
 | |
|       || ((((c) & 0x00ffff00) \
 | |
| 	   == ((PCI_CLASS_MULTIMEDIA << 16) | (PCI_SUBCLASS_MULTIMEDIA_VIDEO << 8)))) )
 | |
| 
 | |
| #define IS_VGA(c) \
 | |
|     (((c) & 0x00ffff00) \
 | |
| 	 == ((PCI_CLASS_DISPLAY << 16) | (PCI_SUBCLASS_DISPLAY_VGA << 8)))
 | |
| 
 | |
| void
 | |
| xf86FormatPciBusNumber(int busnum, char *buffer)
 | |
| {
 | |
|     /* 'buffer' should be at least 8 characters long */
 | |
|     if (busnum < 256)
 | |
| 	sprintf(buffer, "%d", busnum);
 | |
|     else
 | |
| 	sprintf(buffer, "%d@%d", busnum & 0x00ff, busnum >> 8);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xf86Bus.c interface
 | |
|  */
 | |
| 
 | |
| void
 | |
| xf86PciProbe(void)
 | |
| {
 | |
|     int i = 0, k;
 | |
|     int num = 0;
 | |
|     struct pci_device *info;
 | |
|     struct pci_device_iterator *iter;
 | |
|     struct pci_device ** xf86PciVideoInfo = NULL;
 | |
| 
 | |
| 
 | |
|     if (!xf86scanpci()) {
 | |
| 	xf86PciVideoInfo = NULL;
 | |
| 	return;
 | |
|     }
 | |
| 
 | |
|     iter = pci_slot_match_iterator_create(& xf86IsolateDevice);
 | |
|     while ((info = pci_device_next(iter)) != NULL) {
 | |
| 	if (PCIINFOCLASSES(info->device_class)) {
 | |
| 	    num++;
 | |
| 	    xf86PciVideoInfo = xnfrealloc(xf86PciVideoInfo,
 | |
| 					  (sizeof(struct pci_device *)
 | |
| 					   * (num + 1)));
 | |
| 	    xf86PciVideoInfo[num] = NULL;
 | |
| 	    xf86PciVideoInfo[num - 1] = info;
 | |
| 
 | |
| 	    pci_device_probe(info);
 | |
| #ifdef HAVE_PCI_DEVICE_IS_BOOT_VGA
 | |
| 	    if (pci_device_is_boot_vga(info)) {
 | |
|                 primaryBus.type = BUS_PCI;
 | |
|                 primaryBus.id.pci = info;
 | |
|             }
 | |
| #endif
 | |
| 	    info->user_data = 0;
 | |
| 	}
 | |
|     }
 | |
|     free(iter);
 | |
| 
 | |
|     /* If we haven't found a primary device try a different heuristic */
 | |
|     if (primaryBus.type == BUS_NONE && num) {
 | |
| 	for (i = 0; i < num; i++) {
 | |
| 	    uint16_t  command;
 | |
| 
 | |
| 	    info = xf86PciVideoInfo[i];
 | |
| 	    pci_device_cfg_read_u16(info, & command, 4);
 | |
| 
 | |
| 	    if ((command & PCI_CMD_MEM_ENABLE) 
 | |
| 		&& ((num == 1) || IS_VGA(info->device_class))) {
 | |
| 		if (primaryBus.type == BUS_NONE) {
 | |
| 		    primaryBus.type = BUS_PCI;
 | |
| 		    primaryBus.id.pci = info;
 | |
| 		} else {
 | |
| 		    xf86Msg(X_NOTICE,
 | |
| 			    "More than one possible primary device found\n");
 | |
| 		    primaryBus.type ^= (BusType)(-1);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     /* Print a summary of the video devices found */
 | |
|     for (k = 0; k < num; k++) {
 | |
| 	const char *vendorname = NULL, *chipname = NULL;
 | |
| 	const char *prim = " ";
 | |
| 	Bool memdone = FALSE, iodone = FALSE;
 | |
| 
 | |
| 
 | |
| 	info = xf86PciVideoInfo[k];
 | |
| 
 | |
| 	vendorname = pci_device_get_vendor_name( info );
 | |
| 	chipname = pci_device_get_device_name( info );
 | |
| 
 | |
| 	if ((!vendorname || !chipname) &&
 | |
| 	    !PCIALWAYSPRINTCLASSES(info->device_class))
 | |
| 	    continue;
 | |
| 
 | |
| 	if (xf86IsPrimaryPci(info))
 | |
| 	    prim = "*";
 | |
| 
 | |
| 	xf86Msg(X_PROBED, "PCI:%s(%u:%u:%u:%u) %04x:%04x:%04x:%04x ", prim,
 | |
| 		info->domain, info->bus, info->dev, info->func,
 | |
| 		info->vendor_id, info->device_id,
 | |
| 		info->subvendor_id, info->subdevice_id);
 | |
| 
 | |
| 	if (vendorname)
 | |
| 	    xf86ErrorF("%s ", vendorname);
 | |
| 
 | |
| 	if (chipname)
 | |
| 	    xf86ErrorF("%s ", chipname);
 | |
| 
 | |
| 	xf86ErrorF("rev %d", info->revision);
 | |
| 
 | |
| 	for (i = 0; i < 6; i++) {
 | |
| 	    struct pci_mem_region * r = & info->regions[i];
 | |
| 
 | |
| 	    if ( r->size && ! r->is_IO ) {
 | |
| 		if (!memdone) {
 | |
| 		    xf86ErrorF(", Mem @ ");
 | |
| 		    memdone = TRUE;
 | |
| 		} else
 | |
| 		    xf86ErrorF(", ");
 | |
| 		xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size);
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < 6; i++) {
 | |
| 	    struct pci_mem_region * r = & info->regions[i];
 | |
| 
 | |
| 	    if ( r->size && r->is_IO ) {
 | |
| 		if (!iodone) {
 | |
| 		    xf86ErrorF(", I/O @ ");
 | |
| 		    iodone = TRUE;
 | |
| 		} else
 | |
| 		    xf86ErrorF(", ");
 | |
| 		xf86ErrorF("0x%08lx/%ld", (long)r->base_addr, (long)r->size);
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	if ( info->rom_size ) {
 | |
| 	    xf86ErrorF(", BIOS @ 0x\?\?\?\?\?\?\?\?/%ld", (long)info->rom_size);
 | |
| 	}
 | |
| 
 | |
| 	xf86ErrorF("\n");
 | |
|     }
 | |
|     xfree(xf86PciVideoInfo);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * If the slot requested is already in use, return -1.
 | |
|  * Otherwise, claim the slot for the screen requesting it.
 | |
|  */
 | |
| 
 | |
| int
 | |
| xf86ClaimPciSlot(struct pci_device * d, DriverPtr drvp,
 | |
| 		 int chipset, GDevPtr dev, Bool active)
 | |
| {
 | |
|     EntityPtr p = NULL;
 | |
|     int num;
 | |
|     
 | |
|     if (xf86CheckPciSlot(d)) {
 | |
| 	num = xf86AllocateEntity();
 | |
| 	p = xf86Entities[num];
 | |
| 	p->driver = drvp;
 | |
| 	p->chipset = chipset;
 | |
| 	p->bus.type = BUS_PCI;
 | |
| 	p->bus.id.pci = d;
 | |
| 	p->active = active;
 | |
| 	p->inUse = FALSE;
 | |
| 	if (dev)
 | |
|             xf86AddDevToEntity(num, dev);
 | |
| 	pciSlotClaimed = TRUE;
 | |
| 
 | |
| 	if (active) {
 | |
| 	    /* Map in this domain's I/O space */
 | |
| 	   p->domainIO = xf86MapLegacyIO(d);
 | |
| 	}
 | |
| 	
 | |
|  	return num;
 | |
|     } else
 | |
|  	return -1;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Unclaim PCI slot, e.g. if probing failed, so that a different driver can claim.
 | |
|  */
 | |
| void
 | |
| xf86UnclaimPciSlot(struct pci_device *d)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < xf86NumEntities; i++) {
 | |
| 	const EntityPtr p = xf86Entities[i];
 | |
| 
 | |
| 	if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
 | |
| 	    /* Probably the slot should be deallocated? */
 | |
| 	    p->bus.type = BUS_NONE;
 | |
| 	    return;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Parse a BUS ID string, and return the PCI bus parameters if it was
 | |
|  * in the correct format for a PCI bus id.
 | |
|  */
 | |
| 
 | |
| Bool
 | |
| xf86ParsePciBusString(const char *busID, int *bus, int *device, int *func)
 | |
| {
 | |
|     /*
 | |
|      * The format is assumed to be "bus[@domain]:device[:func]", where domain,
 | |
|      * bus, device and func are decimal integers.  domain and func may be
 | |
|      * omitted and assumed to be zero, although doing this isn't encouraged.
 | |
|      */
 | |
| 
 | |
|     char *p, *s, *d;
 | |
|     const char *id;
 | |
|     int i;
 | |
| 
 | |
|     if (StringToBusType(busID, &id) != BUS_PCI)
 | |
| 	return FALSE;
 | |
| 
 | |
|     s = xstrdup(id);
 | |
|     p = strtok(s, ":");
 | |
|     if (p == NULL || *p == 0) {
 | |
| 	xfree(s);
 | |
| 	return FALSE;
 | |
|     }
 | |
|     d = strpbrk(p, "@");
 | |
|     if (d != NULL) {
 | |
| 	*(d++) = 0;
 | |
| 	for (i = 0; d[i] != 0; i++) {
 | |
| 	    if (!isdigit(d[i])) {
 | |
| 		xfree(s);
 | |
| 		return FALSE;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     for (i = 0; p[i] != 0; i++) {
 | |
| 	if (!isdigit(p[i])) {
 | |
| 	    xfree(s);
 | |
| 	    return FALSE;
 | |
| 	}
 | |
|     }
 | |
|     *bus = atoi(p);
 | |
|     if (d != NULL && *d != 0)
 | |
| 	*bus += atoi(d) << 8;
 | |
|     p = strtok(NULL, ":");
 | |
|     if (p == NULL || *p == 0) {
 | |
| 	xfree(s);
 | |
| 	return FALSE;
 | |
|     }
 | |
|     for (i = 0; p[i] != 0; i++) {
 | |
| 	if (!isdigit(p[i])) {
 | |
| 	    xfree(s);
 | |
| 	    return FALSE;
 | |
| 	}
 | |
|     }
 | |
|     *device = atoi(p);
 | |
|     *func = 0;
 | |
|     p = strtok(NULL, ":");
 | |
|     if (p == NULL || *p == 0) {
 | |
| 	xfree(s);
 | |
| 	return TRUE;
 | |
|     }
 | |
|     for (i = 0; p[i] != 0; i++) {
 | |
| 	if (!isdigit(p[i])) {
 | |
| 	    xfree(s);
 | |
| 	    return FALSE;
 | |
| 	}
 | |
|     }
 | |
|     *func = atoi(p);
 | |
|     xfree(s);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Compare a BUS ID string with a PCI bus id.  Return TRUE if they match.
 | |
|  */
 | |
| 
 | |
| Bool
 | |
| xf86ComparePciBusString(const char *busID, int bus, int device, int func)
 | |
| {
 | |
|     int ibus, idevice, ifunc;
 | |
| 
 | |
|     if (xf86ParsePciBusString(busID, &ibus, &idevice, &ifunc)) {
 | |
| 	return bus == ibus && device == idevice && func == ifunc;
 | |
|     } else {
 | |
| 	return FALSE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xf86IsPrimaryPci() -- return TRUE if primary device
 | |
|  * is PCI and bus, dev and func numbers match.
 | |
|  */
 | |
|  
 | |
| Bool
 | |
| xf86IsPrimaryPci(struct pci_device *pPci)
 | |
| {
 | |
|     return ((primaryBus.type == BUS_PCI) && (pPci == primaryBus.id.pci));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xf86GetPciInfoForEntity() -- Get the pciVideoRec of entity.
 | |
|  */
 | |
| struct pci_device *
 | |
| xf86GetPciInfoForEntity(int entityIndex)
 | |
| {
 | |
|     EntityPtr p;
 | |
|     
 | |
|     if (entityIndex >= xf86NumEntities)
 | |
| 	return NULL;
 | |
| 
 | |
|     p = xf86Entities[entityIndex];
 | |
|     return (p->bus.type == BUS_PCI) ? p->bus.id.pci : NULL;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * xf86CheckPciMemBase() checks that the memory base value matches one of the
 | |
|  * PCI base address register values for the given PCI device.
 | |
|  */
 | |
| Bool
 | |
| xf86CheckPciMemBase( struct pci_device * pPci, memType base )
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < 6; i++)
 | |
| 	if (base == pPci->regions[i].base_addr)
 | |
| 	    return TRUE;
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Check if the slot requested is free.  If it is already in use, return FALSE.
 | |
|  */
 | |
| 
 | |
| Bool
 | |
| xf86CheckPciSlot(const struct pci_device *d)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < xf86NumEntities; i++) {
 | |
| 	const EntityPtr p = xf86Entities[i];
 | |
| 
 | |
| 	if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
 | |
| 	    return FALSE;
 | |
| 	}
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 |