home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
lxapi32.zip
/
PCI
/
pci.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-04-26
|
27KB
|
968 lines
/* $Id: pci.c,v 1.2 2002/04/26 23:09:35 smilcke Exp $ */
/*
* pci.c
* Autor: Stefan Milcke
* Erstellt am: 25.10.2001
* Letzte Aenderung am: 09.04.2002
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
#ifndef FAR
#define FAR_LDEFOS2
#endif
#include <ldefos2.h>
#ifdef FAR_LDEFOS2
#undef FAR
#undef FAR_LDEFOS2
#endif
#define INCL_NOPMAPI
#include <os2.h>
#include <lxrmcall.h>
#define LINUX
#include <stacktoflat.h>
#define PCI_CONFIG_ADDRESS 0xCF8
#define PCI_CONFIG_DATA 0xCFC
#define PCI_CONFIG_ENABLE 0x80000000
LIST_HEAD(pci_root_buses);
LIST_HEAD(pci_devices);
LIST_HEAD(pci_drivers);
extern void dev_probe_lock(void);
extern void dev_probe_unlock(void);
#ifdef TARGET_OS2
extern int dopcifixups;
extern int dopcienable;
extern int dopcisetmaster;
extern int dopcisetpowerstate;
extern int dopciupdateresource;
MODULE_PARM_LIST_HEAD(pcidrv_parms)
MODULE_PARM(dopcifixups,"i")
MODULE_PARM(dopcienable,"i")
MODULE_PARM(dopcisetmaster,"i")
MODULE_PARM(dopcisetpowerstate,"i")
MODULE_PARM(dopciupdateresource,"i")
MODULE_PARM_LIST_TAIL(pcidrv_parms)
#endif
//----------------------------- pci_enable_device ------------------------------
int pci_enable_device(struct pci_dev *dev)
{
int err;
#ifdef TARGET_OS2
if(0==dopcienable)
return 0;
#endif
pci_set_power_state(dev,0);
if((err=pcibios_enable_device(dev))<0)
return err;
return 0;
}
//----------------------------- pci_disable_device -----------------------------
void pci_disable_device(struct pci_dev *dev)
{
u16 pci_command;
pci_read_config_word(dev,PCI_COMMAND,&pci_command);
if(pci_command & PCI_COMMAND_MASTER)
{
pci_command&=~PCI_COMMAND_MASTER;
#ifdef TARGET_OS2
if(0!=dopcienable)
#endif
pci_write_config_word(dev,PCI_COMMAND,pci_command);
}
}
//------------------------------ pci_match_device ------------------------------
const struct pci_device_id *pci_match_device(const struct pci_device_id *ids
,const struct pci_dev *dev)
{
while(ids->vendor||ids->subvendor||ids->class_mask)
{
if((ids->vendor==PCI_ANY_ID || ids->vendor==dev->vendor) &&
(ids->device==PCI_ANY_ID || ids->device==dev->device) &&
(ids->subvendor==PCI_ANY_ID || ids->subvendor==dev->subsystem_vendor) &&
(ids->subdevice==PCI_ANY_ID || ids->subdevice==dev->subsystem_device) &&
!((ids->pciclass ^ dev->pciclass) & ids->class_mask))
return ids;
ids++;
}
return NULL;
}
#ifdef TARGET_OS2
unsigned long OS2_pci_announce_device(struct pci_driver *drv,struct pci_dev *dev);
#endif
//---------------------------- pci_announce_device -----------------------------
static int pci_announce_device(struct pci_driver *drv,struct pci_dev *dev)
{
const struct pci_device_id *id;
int ret=0;
if(drv->id_table)
{
id=pci_match_device(drv->id_table,dev);
if(!id)
{
ret=0;
goto out;
}
}
else
id=NULL;
dev_probe_lock();
if(drv->probe(dev,id)>=0)
{
dev->driver=drv;
#ifdef TARGET_OS2
OS2_pci_announce_device(drv,dev);
#endif
ret=1;
}
dev_probe_unlock();
out:
return ret;
}
#ifdef TARGET_OS2
unsigned long OS2_pci_register_driver(struct pci_driver *drv);
unsigned long OS2_pci_unregister_driver(struct pci_driver *drv);
#endif
//---------------------------- pci_register_driver -----------------------------
int pci_register_driver(struct pci_driver *drv)
{
struct pci_dev *dev;
int count=0;
list_add_tail(&drv->node,&pci_drivers);
#ifdef TARGET_OS2
OS2_pci_register_driver(drv);
#endif
pci_for_each_dev(dev)
{
if(!pci_dev_driver(dev))
count+=pci_announce_device(drv,dev);
}
return count;
}
//--------------------------- pci_unregister_driver ----------------------------
void pci_unregister_driver(struct pci_driver *drv)
{
struct pci_dev *dev;
list_del(&drv->node);
pci_for_each_dev(dev)
{
if(dev->driver==drv)
{
if(drv->remove)
drv->remove(dev);
dev->driver=NULL;
}
}
#ifdef TARGET_OS2
OS2_pci_unregister_driver(drv);
#endif
}
//----------------------- pci_announce_device_to_drivers -----------------------
void pci_announce_device_to_drivers(struct pci_dev *dev)
{
struct list_head *ln;
for(ln=pci_drivers.next;ln!=&pci_drivers;ln=ln->next)
{
struct pci_driver *drv=list_entry(ln,struct pci_driver,node);
if(drv->remove && pci_announce_device(drv,dev))
break;
}
// run_sbin_hotplug(dev,TRUE);
}
//----------------------------- pci_insert_device ------------------------------
void pci_insert_device(struct pci_dev *dev,struct pci_bus *bus)
{
list_add_tail(&dev->bus_list,&bus->devices);
list_add_tail(&dev->global_list,&pci_devices);
pci_announce_device_to_drivers(dev);
}
//----------------------------- pci_free_resources -----------------------------
static void pci_free_resources(struct pci_dev *dev)
{
int i;
for(i=0;i<PCI_NUM_RESOURCES;i++)
{
struct resource *res=dev->resource+i;
if(res->parent)
release_resource(res);
}
}
//----------------------------- pci_remove_device ------------------------------
void pci_remove_device(struct pci_dev *dev)
{
if(dev->driver)
{
if(dev->driver->remove)
dev->driver->remove(dev);
dev->driver=NULL;
}
list_del(&dev->bus_list);
list_del(&dev->global_list);
pci_free_resources(dev);
// run_sbin_hotplug(dev,FALSE);
}
static struct pci_driver pci_compat_driver={0};
//------------------------------- pci_dev_driver -------------------------------
struct pci_driver *pci_dev_driver(const struct pci_dev *dev)
{
if(dev->driver)
return dev->driver;
else
{
int i;
for(i=0;i<=PCI_ROM_RESOURCE;i++)
if(dev->resource[i].flags & IORESOURCE_BUSY)
{
pci_compat_driver.name="compat";
return &pci_compat_driver;
}
}
return NULL;
}
//------------------------------- pci_find_slot --------------------------------
struct pci_dev *pci_find_slot(unsigned int bus,unsigned int devfn)
{
struct pci_dev *dev;
pci_for_each_dev(dev)
{
if(dev->bus->number==bus && dev->devfn==devfn)
return dev;
}
return NULL;
}
//------------------------------ pci_find_subsys -------------------------------
struct pci_dev *pci_find_subsys(unsigned int vendor,unsigned int device
,unsigned int ss_vendor,unsigned int ss_device
,const struct pci_dev *from)
{
struct list_head *n=from ? from->global_list.next : pci_devices.next;
while(n!=&pci_devices)
{
struct pci_dev *dev=pci_dev_g(n);
if((vendor==PCI_ANY_ID || dev->vendor==vendor) &&
(device==PCI_ANY_ID || dev->device==device) &&
(ss_vendor==PCI_ANY_ID || dev->subsystem_vendor==ss_vendor) &&
(ss_device==PCI_ANY_ID || dev->subsystem_device==ss_device))
return dev;
n=n->next;
}
return NULL;
}
//------------------------------ pci_find_device -------------------------------
struct pci_dev *pci_find_device(unsigned int vendor,unsigned int device
,const struct pci_dev *from)
{
return pci_find_subsys(vendor,device,PCI_ANY_ID,PCI_ANY_ID,from);
}
//------------------------------- pci_find_class -------------------------------
struct pci_dev *pci_find_class(unsigned int pciclass, const struct pci_dev *from)
{
struct list_head *n = from ? from->global_list.next : pci_devices.next;
while (n != &pci_devices)
{
struct pci_dev *dev = pci_dev_g(n);
if (dev->pciclass == pciclass)
return dev;
n = n->next;
}
return NULL;
}
//---------------------------- pci_find_capability -----------------------------
int pci_find_capability(struct pci_dev *dev, int cap)
{
u16 status;
u8 pos, id;
int ttl = 48;
pci_read_config_word(dev, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
switch (dev->hdr_type)
{
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);
break;
case PCI_HEADER_TYPE_CARDBUS:
pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos);
break;
default:
return 0;
}
while (ttl-- && pos >= 0x40)
{
pos &= ~3;
pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
if (id == 0xff)
break;
if (id == cap)
return pos;
pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);
}
return 0;
}
//-------------------------- pci_find_parent_resource --------------------------
struct resource *pci_find_parent_resource(const struct pci_dev *dev
,struct resource *res)
{
const struct pci_bus *bus=dev->bus;
int i;
struct resource *best=NULL;
for(i=0;i<4;i++)
{
struct resource *r=bus->resource[i];
if(!r)
continue;
if(res->start && !(res->start>=r->start && res->end<=r->end))
continue;
if((res->flags^r->flags)&(IORESOURCE_IO | IORESOURCE_MEM))
continue;
if(!((res->flags^r->flags)&IORESOURCE_PREFETCH))
return r;
if((res->flags&IORESOURCE_PREFETCH)&&!(r->flags&IORESOURCE_PREFETCH))
best=r;
}
return best;
}
//---------------------------- pci_set_power_state -----------------------------
int pci_set_power_state(struct pci_dev *dev,int state)
{
int pm;
u16 pmcsr;
#ifdef TARGET_OS2
if(0==dopcisetpowerstate)
return 0;
#endif
if(state>3)
state=3;
if(state>0 && dev->current_state>state)
return -EINVAL;
else if(dev->current_state==state)
return 0;
pm=pci_find_capability(dev,PCI_CAP_ID_PM);
if(!pm)
return -EIO;
if(state==1 || state==2)
{
u16 pmc;
pci_read_config_word(dev,pm+PCI_PM_PMC,&pmc);
if(state==1 && !(pmc&PCI_PM_CAP_D1))
return -EIO;
else if(state==2 && !(pmc&PCI_PM_CAP_D2))
return -EIO;
}
if(dev->current_state>=3)
pmcsr=0;
else
{
pci_read_config_word(dev,pm+PCI_PM_CTRL,&pmcsr);
pmcsr&=~PCI_PM_CTRL_STATE_MASK;
pmcsr|=state;
}
pci_write_config_word(dev,pm+PCI_PM_CTRL,pmcsr);
if(state==3 || dev->current_state==3)
{
// Incomplete (SM)
// set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
}
else if(state==2 || dev->current_state==2)
udelay(200);
dev->current_state=state;
return 0;
}
#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
//---------------------------- pci_read_config_byte ----------------------------
int pci_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inb(0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
//---------------------------- pci_read_config_word ----------------------------
int pci_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inw(0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
//--------------------------- pci_read_config_dword ----------------------------
int pci_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inl(0xCFC);
return PCIBIOS_SUCCESSFUL;
}
//--------------------------- pci_write_config_byte ----------------------------
int pci_write_config_byte(struct pci_dev *dev, int where, u8 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outb(value, 0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
//--------------------------- pci_write_config_word ----------------------------
int pci_write_config_word(struct pci_dev *dev, int where, u16 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outw(value, 0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
//--------------------------- pci_write_config_dword ---------------------------
int pci_write_config_dword(struct pci_dev *dev, int where, u32 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outl(value, 0xCFC);
return PCIBIOS_SUCCESSFUL;
}
//-------------------------- pci_calc_resource_flags ---------------------------
static __inline__ unsigned int pci_calc_resource_flags(unsigned int flags)
{
if(flags&PCI_BASE_ADDRESS_SPACE_IO)
return IORESOURCE_IO;
if(flags&PCI_BASE_ADDRESS_MEM_PREFETCH)
return IORESOURCE_MEM | IORESOURCE_PREFETCH;
return IORESOURCE_MEM;
}
//---------------------------------- pci_size ----------------------------------
static u32 pci_size(u32 base,unsigned long mask)
{
u32 size=mask&base; // find the significant bits
size=size&~(size-1); // get the lowest of them to find the decode size
return size-1; // extend=size-1
}
//------------------------------- pci_set_master -------------------------------
void pci_set_master(struct pci_dev *dev)
{
u16 cmd;
pci_read_config_word(dev,PCI_COMMAND,&cmd);
if(!(cmd&PCI_COMMAND_MASTER))
{
// DBG("PCI: Enabling bus mastering for device %s\n",dev->slot_name);
cmd|=PCI_COMMAND_MASTER;
#ifdef TARGET_OS2
if(0!=dopcisetmaster)
#endif
pci_write_config_word(dev,PCI_COMMAND,cmd);
}
pcibios_set_master(dev);
}
//------------------------------- pci_read_bases -------------------------------
static void pci_read_bases(struct pci_dev *dev,unsigned int howmany,int rom)
{
unsigned int pos,reg,next;
u32 l,sz;
struct resource *res;
for(pos=0;pos<howmany;pos=next)
{
next=pos+1;
res=&dev->resource[pos];
res->name=dev->name;
reg=PCI_BASE_ADDRESS_0 + (pos << 2);
pci_read_config_dword(dev,reg,&l);
pci_write_config_dword(dev,reg,~0);
pci_read_config_dword(dev,reg,&sz);
pci_write_config_dword(dev,reg,l);
if(!sz || sz==0xffffffff)
continue;
if(l==0xffffffff)
l=0;
if((l&PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_MEMORY)
{
res->start=l&PCI_BASE_ADDRESS_MEM_MASK;
sz=pci_size(sz,PCI_BASE_ADDRESS_MEM_MASK);
}
else
{
res->start=l&PCI_BASE_ADDRESS_IO_MASK;
sz=pci_size(sz,PCI_BASE_ADDRESS_IO_MASK & 0xffff);
}
res->end=res->start+(unsigned long)sz;
res->flags|=(l&0xf) | pci_calc_resource_flags(l);
if((l&(PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
==(PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64))
{
pci_read_config_dword(dev,reg+4,&l);
next++;
#if BITS_PER_LONG==64
res->start|=((unsigned long)l)<<32;
res->end=res->start+sz;
pci_write_config_dword(dev,reg+4,~0);
pci_read_config_dword(dev,reg+4,&sz);
pci_write_config_dword(dev,reg+4,l);
if(~sz)
res->end=res->start+0xffffffff+(((unsigned long)~sz)<<32);
#else
if(l)
{
res->start=0;
res->flags=0;
continue;
}
#endif
}
}
if(rom)
{
dev->rom_base_reg=rom;
res=&dev->resource[PCI_ROM_RESOURCE];
pci_read_config_dword(dev,rom,&l);
pci_write_config_dword(dev,rom,~PCI_ROM_ADDRESS_ENABLE);
pci_read_config_dword(dev,rom,&sz);
pci_write_config_dword(dev,rom,l);
if(l==0xffffffff)
l=0;
if(sz && sz!=0xffffffff)
{
res->flags=(l&PCI_ROM_ADDRESS_ENABLE)
| IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
res->start=l&PCI_ROM_ADDRESS_MASK;
sz=pci_size(sz,PCI_ROM_ADDRESS_MASK);
res->end=res->start+(unsigned long)sz;
}
res->name=dev->name;
}
}
//--------------------------- pci_read_bridge_bases ----------------------------
void __init pci_read_bridge_bases(struct pci_bus *child)
{
struct pci_dev *dev=child->self;
u8 io_base_lo,io_limit_lo;
u16 mem_base_lo,mem_limit_lo;
unsigned long base,limit;
struct resource *res;
int i;
if(!dev)
return;
for(i=0;i<3;i++)
child->resource[i]=&dev->resource[PCI_BRIDGE_RESOURCES+i];
res=child->resource[0];
pci_read_config_byte(dev,PCI_IO_BASE,&io_base_lo);
pci_read_config_byte(dev,PCI_IO_LIMIT,&io_limit_lo);
base=(io_base_lo & PCI_IO_RANGE_MASK)<<8;
limit=(io_limit_lo & PCI_IO_RANGE_MASK)<<8;
if((base&PCI_IO_RANGE_TYPE_MASK)==PCI_IO_RANGE_TYPE_32)
{
u16 io_base_hi,io_limit_hi;
pci_read_config_word(dev,PCI_IO_BASE_UPPER16,&io_base_hi);
pci_read_config_word(dev,PCI_IO_LIMIT_UPPER16,&io_limit_hi);
base|=(io_base_hi<<16);
limit|=(io_limit_hi<<16);
}
if(base && base <= limit)
{
res->flags=(io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
res->start=base;
res->end=limit+0xfff;
res->name=child->name; // ??? (SM)
}
else
{
// Ugh. We don't know enough about this bridge. Just assume
// that it's entirely transparent
CPK(printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n",0));
child->resource[0]=child->parent->resource[0];
}
res=child->resource[1];
pci_read_config_word(dev,PCI_MEMORY_BASE,&mem_base_lo);
pci_read_config_word(dev,PCI_MEMORY_LIMIT,&mem_limit_lo);
base=(mem_base_lo & PCI_MEMORY_RANGE_MASK)<<16;
limit=(mem_limit_lo & PCI_MEMORY_RANGE_MASK)<<16;
if(base && base <= limit)
{
res->flags=(mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
res->start=base;
res->end=limit+0xfffff;
res->name=child->name; // ??? (SM)
}
else
{
// Ugh. We don't know enough about this bridge. Just assume
// that it's entirely transparent
CPK(printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n",1));
child->resource[1]=child->parent->resource[1];
}
res=child->resource[2];
pci_read_config_word(dev,PCI_PREF_MEMORY_BASE,&mem_base_lo);
pci_read_config_word(dev,PCI_PREF_MEMORY_LIMIT,&mem_limit_lo);
base=(mem_base_lo & PCI_PREF_RANGE_MASK)<<16;
limit=(mem_limit_lo & PCI_PREF_RANGE_MASK)<<16;
if((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK)==PCI_PREF_RANGE_TYPE_64)
{
u32 mem_base_hi,mem_limit_hi;
pci_read_config_dword(dev,PCI_PREF_BASE_UPPER32,&mem_base_hi);
pci_read_config_dword(dev,PCI_PREF_LIMIT_UPPER32,&mem_limit_hi);
#if BITS_PER_LONG==64
base |=((long)mem_base_hi)<<32;
limit |=((long)mem_limit_hi)<<32;
#else
if(mem_base_hi || mem_limit_hi)
{
CPK(printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n",child->name));
return;
}
#endif
}
if(base & base <= limit)
{
res->flags=(mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
res->start=base;
res->end=limit+0xfffff;
res->name=child->name; // ??? (SM)
}
else
{
// Ugh. We don't know enough about this bridge. Just assume
// that it's entirely transparent
CPK(printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n",2));
child->resource[2]=child->parent->resource[2];
}
}
//------------------------------- pci_alloc_bus --------------------------------
static struct pci_bus *pci_alloc_bus(void)
{
struct pci_bus *b;
b=kmalloc(sizeof(*b),GFP_KERNEL);
if(b)
{
memset(b,0,sizeof(*b));
INIT_LIST_HEAD(&b->children);
INIT_LIST_HEAD(&b->devices);
}
return b;
}
//------------------------------ pci_add_new_bus -------------------------------
static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent
,struct pci_dev *dev
,int busnr)
{
struct pci_bus *child;
int i;
child=pci_alloc_bus();
list_add_tail(&child->node,&parent->children);
child->self=dev;
dev->subordinate=child;
child->parent=parent;
child->ops=parent->ops;
child->sysdata=parent->sysdata;
child->number=child->secondary=busnr;
child->primary=parent->secondary;
child->subordinate=0xff;
for(i=0;i<4;i++)
child->resource[i]=&dev->resource[PCI_BRIDGE_RESOURCES+i];
return child;
}
static unsigned int __init pci_do_scan_bus(struct pci_bus *bus);
//------------------------------ pci_scan_bridge -------------------------------
static int __init pci_scan_bridge(struct pci_bus *bus,struct pci_dev *dev
,int maxb,int pass)
{
unsigned int buses;
unsigned short cr;
struct pci_bus *child;
int is_cardbus=(dev->hdr_type==PCI_HEADER_TYPE_CARDBUS);
pci_read_config_dword(dev,PCI_PRIMARY_BUS,&buses);
if((buses&0xffff00) && !pcibios_assign_all_busses())
{
if(pass)
return maxb;
child=(struct pci_bus *)pci_add_new_bus(bus,dev,0);
child->primary=buses&0xFF;
child->secondary=(buses>>8)&0xFF;
child->subordinate=(buses>>16)&0xFF;
child->number=child->secondary;
if(!is_cardbus)
{
unsigned int cmax=pci_do_scan_bus(child);
if(cmax>maxb)
maxb=cmax;
}
else
{
unsigned int cmax=child->subordinate;
if(cmax>maxb)
maxb=cmax;
}
}
else
{
if(!pass)
return maxb;
pci_read_config_word(dev,PCI_COMMAND,&cr);
pci_write_config_word(dev,PCI_COMMAND,0x0000);
pci_write_config_word(dev,PCI_COMMAND,0xFFFF);
child=(struct pci_bus *)pci_add_new_bus(bus,dev,++maxb);
buses=(buses&0xff000000)
|((unsigned int)(child->primary)<<0)
|((unsigned int)(child->secondary)<<8)
|((unsigned int)(child->subordinate)<<16);
pci_write_config_dword(dev,PCI_PRIMARY_BUS,buses);
if(!is_cardbus)
maxb=pci_do_scan_bus(child);
else
maxb+=3;
child->subordinate=maxb;
pci_write_config_byte(dev,PCI_SUBORDINATE_BUS,maxb);
pci_write_config_word(dev,PCI_COMMAND,cr);
}
sprintf(child->name,(is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"),child->number);
return maxb;
}
//-------------------------------- pci_read_irq --------------------------------
static void pci_read_irq(struct pci_dev *dev)
{
unsigned char irq;
pci_read_config_byte(dev,PCI_INTERRUPT_PIN,&irq);
if(irq)
pci_read_config_byte(dev,PCI_INTERRUPT_LINE,&irq);
dev->irq=irq;
}
//------------------------------ pci_setup_device ------------------------------
int pci_setup_device(struct pci_dev *dev)
{
u32 dclass;
sprintf(dev->slot_name,"%02x:%02x.%d"
,dev->bus->number
,PCI_SLOT(dev->devfn)
,PCI_FUNC(dev->devfn));
sprintf(dev->name,"PCI device %04x:%04x"
,dev->vendor
,dev->device);
pci_read_config_dword(dev,PCI_CLASS_REVISION,&dclass);
dclass >>=8;
dev->pciclass=dclass;
dclass >>=8;
dev->current_state=4;
switch(dev->hdr_type)
{
case PCI_HEADER_TYPE_NORMAL:
if(dclass==PCI_CLASS_BRIDGE_PCI)
goto bad;
pci_read_irq(dev);
pci_read_bases(dev,6,PCI_ROM_ADDRESS);
pci_read_config_word(dev,PCI_SUBSYSTEM_VENDOR_ID,&dev->subsystem_vendor);
pci_read_config_word(dev,PCI_SUBSYSTEM_ID,&dev->subsystem_device);
break;
case PCI_HEADER_TYPE_BRIDGE:
if(dclass!=PCI_CLASS_BRIDGE_PCI)
goto bad;
pci_read_bases(dev,2,PCI_ROM_ADDRESS1);
break;
case PCI_HEADER_TYPE_CARDBUS:
if(dclass!=PCI_CLASS_BRIDGE_CARDBUS)
goto bad;
pci_read_irq(dev);
pci_read_bases(dev,1,0);
pci_read_config_word(dev,PCI_SUBSYSTEM_VENDOR_ID,&dev->subsystem_vendor);
pci_read_config_word(dev,PCI_SUBSYSTEM_ID,&dev->subsystem_device);
break;
default:
return -1;
bad:
dev->pciclass=PCI_CLASS_NOT_DEFINED;
}
return 0;
}
//------------------------------ pci_scan_device -------------------------------
static struct pci_dev *pci_scan_device(struct pci_dev *temp)
{
struct pci_dev *dev;
u32 l;
if(pci_read_config_dword(temp,PCI_VENDOR_ID,&l))
return NULL;
if(l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
return NULL;
dev=kmalloc(sizeof(*dev),GFP_KERNEL);
if(!dev)
return NULL;
memcpy(dev,temp,sizeof(*dev));
dev->vendor=l&0xffff;
dev->device=(l>>16)&0xffff;
// Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
// set this higher, assuming the system even supports it;
dev->dma_mask=0xffffffff;
if(pci_setup_device(dev)<0)
{
kfree(dev);
dev=NULL;
}
#ifdef TARGET_OS2
dev->rm_subadapter=kmalloc(sizeof(struct lxrm_subadapter),0);
memset(dev->rm_subadapter,0,sizeof(struct lxrm_subadapter));
dev->rm_subdevice=kmalloc(sizeof(struct lxrm_subdevice),0);
memset(dev->rm_subdevice,0,sizeof(struct lxrm_subdevice));
#endif
return dev;
}
//------------------------------- pci_scan_slot --------------------------------
struct pci_dev *pci_scan_slot(struct pci_dev *temp)
{
struct pci_bus *bus=temp->bus;
struct pci_dev *dev;
struct pci_dev *first_dev=NULL;
int func=0;
int is_multi=0;
u8 hdr_type;
for(func=0;func<8;func++,temp->devfn++)
{
if(func&&!is_multi)
continue;
if(pci_read_config_byte(temp,PCI_HEADER_TYPE,&hdr_type))
continue;
temp->hdr_type=hdr_type&0x7f;
dev=pci_scan_device(temp);
if(!dev)
continue;
pci_name_device(dev);
if(!func)
{
is_multi=hdr_type&0x80;
first_dev=dev;
}
list_add_tail(&dev->global_list,&pci_devices);
list_add_tail(&dev->bus_list,&bus->devices);
pci_fixup_device(PCI_FIXUP_HEADER,dev);
}
return first_dev;
}
//------------------------------ pci_do_scan_bus -------------------------------
static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
{
unsigned int devfn,maxb,pass;
struct list_head *ln;
struct pci_dev *dev,dev0;
maxb=bus->secondary;
memset(&dev0,0,sizeof(dev0));
dev0.bus=bus;
dev0.sysdata=bus->sysdata;
for(devfn=0;devfn<0x100;devfn+=8)
{
dev0.devfn=devfn;
pci_scan_slot(&dev0);
}
pcibios_fixup_bus(bus);
for(pass=0;pass<2;pass++)
for(ln=bus->devices.next;ln!=&bus->devices;ln=ln->next)
{
dev=pci_dev_b(ln);
if(dev->hdr_type==PCI_HEADER_TYPE_BRIDGE || dev->hdr_type==PCI_HEADER_TYPE_CARDBUS)
maxb=pci_scan_bridge(bus,dev,maxb,pass);
}
// (SM)
return maxb;
}
//------------------------------- pci_bus_exists -------------------------------
int pci_bus_exists(const struct list_head *list,int nr)
{
const struct list_head *l;
for(l=list->next;l!=list;l=l->next)
{
const struct pci_bus *b=pci_bus_b(l);
if(b->number==nr || pci_bus_exists(&b->children,nr))
return 1;
}
return 0;
}
//--------------------------- pci_alloc_primary_bus ----------------------------
struct pci_bus *pci_alloc_primary_bus(int bus)
{
struct pci_bus *b;
if(pci_bus_exists(&pci_root_buses,bus))
{
return NULL;
}
b=pci_alloc_bus();
list_add_tail(&b->node,&pci_root_buses);
b->number=b->secondary=bus;
b->resource[0]=&ioport_resource;
b->resource[1]=&iomem_resource;
return b;
}
//-------------------------------- pci_scan_bus --------------------------------
struct pci_bus *pci_scan_bus(int bus,struct pci_ops *ops,void *sysdata)
{
struct pci_bus *b=pci_alloc_primary_bus(bus);
if(b)
{
b->sysdata=sysdata;
b->ops=ops;
b->subordinate=pci_do_scan_bus(b);
}
return b;
}
#ifdef TARGET_OS2
void pci_name_device_free(void);
#endif
//---------------------------------- pci_init ----------------------------------
void pci_init(void)
{
struct pci_dev *dev;
pcibios_init();
pci_for_each_dev(dev)
pci_fixup_device(PCI_FIXUP_FINAL,dev);
#ifdef CONFIG_PM
pm_register(PM_PCI_DEV,0,pci_pm_callback);
#endif
#ifdef TARGET_OS2
pci_name_device_free();
#endif
}