2005-04-17 02:20:36 +04:00
/*
* Bus & driver management routines for devices within
* a MacIO ASIC . Interface to new driver model mostly
* stolen from the PCI version .
*
2005-11-23 09:59:04 +03:00
* Copyright ( C ) 2005 Ben . Herrenschmidt ( benh @ kernel . crashing . org )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
2005-04-17 02:20:36 +04:00
* TODO :
*
* - Don ' t probe below media bay by default , but instead provide
* some hooks for media bay to dynamically add / remove it ' s own
* sub - devices .
*/
# include <linux/config.h>
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/pci_ids.h>
# include <linux/init.h>
# include <linux/module.h>
2005-10-31 02:03:48 +03:00
# include <linux/slab.h>
2005-04-17 02:20:36 +04:00
# include <asm/machdep.h>
# include <asm/macio.h>
# include <asm/pmac_feature.h>
# include <asm/prom.h>
# include <asm/pci-bridge.h>
# undef DEBUG
# define MAX_NODE_NAME_SIZE (BUS_ID_SIZE - 12)
static struct macio_chip * macio_on_hold ;
static int macio_bus_match ( struct device * dev , struct device_driver * drv )
{
struct macio_dev * macio_dev = to_macio_device ( dev ) ;
struct macio_driver * macio_drv = to_macio_driver ( drv ) ;
2005-07-06 23:44:41 +04:00
const struct of_device_id * matches = macio_drv - > match_table ;
2005-04-17 02:20:36 +04:00
if ( ! matches )
return 0 ;
return of_match_device ( matches , & macio_dev - > ofdev ) ! = NULL ;
}
struct macio_dev * macio_dev_get ( struct macio_dev * dev )
{
struct device * tmp ;
if ( ! dev )
return NULL ;
tmp = get_device ( & dev - > ofdev . dev ) ;
if ( tmp )
return to_macio_device ( tmp ) ;
else
return NULL ;
}
void macio_dev_put ( struct macio_dev * dev )
{
if ( dev )
put_device ( & dev - > ofdev . dev ) ;
}
static int macio_device_probe ( struct device * dev )
{
int error = - ENODEV ;
struct macio_driver * drv ;
struct macio_dev * macio_dev ;
2005-07-06 23:44:41 +04:00
const struct of_device_id * match ;
2005-04-17 02:20:36 +04:00
drv = to_macio_driver ( dev - > driver ) ;
macio_dev = to_macio_device ( dev ) ;
if ( ! drv - > probe )
return error ;
macio_dev_get ( macio_dev ) ;
match = of_match_device ( drv - > match_table , & macio_dev - > ofdev ) ;
if ( match )
error = drv - > probe ( macio_dev , match ) ;
if ( error )
macio_dev_put ( macio_dev ) ;
return error ;
}
static int macio_device_remove ( struct device * dev )
{
struct macio_dev * macio_dev = to_macio_device ( dev ) ;
struct macio_driver * drv = to_macio_driver ( dev - > driver ) ;
if ( dev - > driver & & drv - > remove )
drv - > remove ( macio_dev ) ;
macio_dev_put ( macio_dev ) ;
return 0 ;
}
static void macio_device_shutdown ( struct device * dev )
{
struct macio_dev * macio_dev = to_macio_device ( dev ) ;
struct macio_driver * drv = to_macio_driver ( dev - > driver ) ;
if ( dev - > driver & & drv - > shutdown )
drv - > shutdown ( macio_dev ) ;
}
2005-04-17 02:25:32 +04:00
static int macio_device_suspend ( struct device * dev , pm_message_t state )
2005-04-17 02:20:36 +04:00
{
struct macio_dev * macio_dev = to_macio_device ( dev ) ;
struct macio_driver * drv = to_macio_driver ( dev - > driver ) ;
if ( dev - > driver & & drv - > suspend )
return drv - > suspend ( macio_dev , state ) ;
return 0 ;
}
static int macio_device_resume ( struct device * dev )
{
struct macio_dev * macio_dev = to_macio_device ( dev ) ;
struct macio_driver * drv = to_macio_driver ( dev - > driver ) ;
if ( dev - > driver & & drv - > resume )
return drv - > resume ( macio_dev ) ;
return 0 ;
}
2005-11-16 11:00:00 +03:00
static int macio_uevent ( struct device * dev , char * * envp , int num_envp ,
2005-07-06 23:45:09 +04:00
char * buffer , int buffer_size )
{
struct macio_dev * macio_dev ;
struct of_device * of ;
2006-02-01 14:05:58 +03:00
char * scratch , * compat , * compat2 ;
2005-07-06 23:45:09 +04:00
int i = 0 ;
2006-02-01 14:05:58 +03:00
int length , cplen , cplen2 , seen = 0 ;
2005-07-06 23:45:09 +04:00
if ( ! dev )
return - ENODEV ;
macio_dev = to_macio_device ( dev ) ;
if ( ! macio_dev )
return - ENODEV ;
of = & macio_dev - > ofdev ;
/* stuff we want to pass to /sbin/hotplug */
2006-02-01 14:05:58 +03:00
envp [ i + + ] = scratch = buffer ;
length = scnprintf ( scratch , buffer_size , " OF_NAME=%s " , of - > node - > name ) ;
2005-07-06 23:45:09 +04:00
+ + length ;
2006-02-01 14:05:58 +03:00
buffer_size - = length ;
if ( ( buffer_size < = 0 ) | | ( i > = num_envp ) )
return - ENOMEM ;
2005-07-06 23:45:09 +04:00
scratch + = length ;
envp [ i + + ] = scratch ;
2006-02-01 14:05:58 +03:00
length = scnprintf ( scratch , buffer_size , " OF_TYPE=%s " , of - > node - > type ) ;
2005-07-06 23:45:09 +04:00
+ + length ;
2006-02-01 14:05:58 +03:00
buffer_size - = length ;
if ( ( buffer_size < = 0 ) | | ( i > = num_envp ) )
return - ENOMEM ;
2005-07-06 23:45:09 +04:00
scratch + = length ;
/* Since the compatible field can contain pretty much anything
* it ' s not really legal to split it out with commas . We split it
* up using a number of environment variables instead . */
compat = ( char * ) get_property ( of - > node , " compatible " , & cplen ) ;
2006-02-01 14:05:58 +03:00
compat2 = compat ;
cplen2 = cplen ;
2005-07-06 23:45:09 +04:00
while ( compat & & cplen > 0 ) {
envp [ i + + ] = scratch ;
2006-02-01 14:05:58 +03:00
length = scnprintf ( scratch , buffer_size ,
2005-07-06 23:45:09 +04:00
" OF_COMPATIBLE_%d=%s " , seen , compat ) ;
2006-02-01 14:05:58 +03:00
+ + length ;
buffer_size - = length ;
if ( ( buffer_size < = 0 ) | | ( i > = num_envp ) )
2005-07-06 23:45:09 +04:00
return - ENOMEM ;
scratch + = length ;
2006-02-01 14:05:58 +03:00
length = strlen ( compat ) + 1 ;
compat + = length ;
cplen - = length ;
2005-07-06 23:45:09 +04:00
seen + + ;
}
envp [ i + + ] = scratch ;
2006-02-01 14:05:58 +03:00
length = scnprintf ( scratch , buffer_size , " OF_COMPATIBLE_N=%d " , seen ) ;
2005-07-06 23:45:09 +04:00
+ + length ;
2006-02-01 14:05:58 +03:00
buffer_size - = length ;
if ( ( buffer_size < = 0 ) | | ( i > = num_envp ) )
return - ENOMEM ;
scratch + = length ;
envp [ i + + ] = scratch ;
length = scnprintf ( scratch , buffer_size , " MODALIAS=of:N%sT%s " ,
of - > node - > name , of - > node - > type ) ;
/* overwrite '\0' */
buffer_size - = length ;
if ( ( buffer_size < = 0 ) | | ( i > = num_envp ) )
return - ENOMEM ;
2005-07-06 23:45:09 +04:00
scratch + = length ;
2006-02-01 14:05:58 +03:00
if ( ! compat2 ) {
compat2 = " " ;
cplen2 = 1 ;
}
while ( cplen2 > 0 ) {
length = snprintf ( scratch , buffer_size , " C%s " , compat2 ) ;
buffer_size - = length ;
if ( buffer_size < = 0 )
return - ENOMEM ;
scratch + = length ;
length = strlen ( compat2 ) + 1 ;
compat2 + = length ;
cplen2 - = length ;
}
2005-07-06 23:45:09 +04:00
envp [ i ] = NULL ;
return 0 ;
}
2005-07-06 23:26:27 +04:00
extern struct device_attribute macio_dev_attrs [ ] ;
2005-04-17 02:20:36 +04:00
struct bus_type macio_bus_type = {
. name = " macio " ,
. match = macio_bus_match ,
2005-11-16 11:00:00 +03:00
. uevent = macio_uevent ,
2006-01-05 17:39:24 +03:00
. probe = macio_device_probe ,
. remove = macio_device_remove ,
. shutdown = macio_device_shutdown ,
2005-04-17 02:20:36 +04:00
. suspend = macio_device_suspend ,
. resume = macio_device_resume ,
2005-07-06 23:26:27 +04:00
. dev_attrs = macio_dev_attrs ,
2005-04-17 02:20:36 +04:00
} ;
static int __init macio_bus_driver_init ( void )
{
return bus_register ( & macio_bus_type ) ;
}
postcore_initcall ( macio_bus_driver_init ) ;
/**
2005-11-23 09:59:04 +03:00
* macio_release_dev - free a macio device structure when all users of it are
* finished .
2005-04-17 02:20:36 +04:00
* @ dev : device that ' s been disconnected
*
2005-11-23 09:59:04 +03:00
* Will be called only by the device core when all users of this macio device
* are done . This currently means never as we don ' t hot remove any macio
* device yet , though that will happen with mediabay based devices in a later
* implementation .
2005-04-17 02:20:36 +04:00
*/
static void macio_release_dev ( struct device * dev )
{
struct macio_dev * mdev ;
mdev = to_macio_device ( dev ) ;
kfree ( mdev ) ;
}
/**
* macio_resource_quirks - tweak or skip some resources for a device
* @ np : pointer to the device node
* @ res : resulting resource
* @ index : index of resource in node
*
* If this routine returns non - null , then the resource is completely
* skipped .
*/
2005-11-23 09:59:04 +03:00
static int macio_resource_quirks ( struct device_node * np , struct resource * res ,
int index )
2005-04-17 02:20:36 +04:00
{
if ( res - > flags & IORESOURCE_MEM ) {
/* Grand Central has too large resource 0 on some machines */
2005-12-13 10:01:21 +03:00
if ( index = = 0 & & ! strcmp ( np - > name , " gc " ) )
2005-04-17 02:20:36 +04:00
res - > end = res - > start + 0x1ffff ;
2005-12-13 10:01:21 +03:00
2005-04-17 02:20:36 +04:00
/* Airport has bogus resource 2 */
if ( index > = 2 & & ! strcmp ( np - > name , " radio " ) )
return 1 ;
2005-12-13 10:01:21 +03:00
# ifndef CONFIG_PPC64
2005-04-17 02:20:36 +04:00
/* DBDMAs may have bogus sizes */
2005-12-13 10:01:21 +03:00
if ( ( res - > start & 0x0001f000 ) = = 0x00008000 )
2005-04-17 02:20:36 +04:00
res - > end = res - > start + 0xff ;
2005-12-13 10:01:21 +03:00
# endif /* CONFIG_PPC64 */
2005-11-23 09:59:04 +03:00
/* ESCC parent eats child resources. We could have added a
* level of hierarchy , but I don ' t really feel the need
* for it
*/
2005-04-17 02:20:36 +04:00
if ( ! strcmp ( np - > name , " escc " ) )
return 1 ;
2005-12-13 10:01:21 +03:00
2005-04-17 02:20:36 +04:00
/* ESCC has bogus resources >= 3 */
2005-11-23 09:59:04 +03:00
if ( index > = 3 & & ! ( strcmp ( np - > name , " ch-a " ) & &
strcmp ( np - > name , " ch-b " ) ) )
2005-04-17 02:20:36 +04:00
return 1 ;
2005-12-13 10:01:21 +03:00
2005-04-17 02:20:36 +04:00
/* Media bay has too many resources, keep only first one */
if ( index > 0 & & ! strcmp ( np - > name , " media-bay " ) )
return 1 ;
2005-12-13 10:01:21 +03:00
2005-04-17 02:20:36 +04:00
/* Some older IDE resources have bogus sizes */
if ( ! ( strcmp ( np - > name , " IDE " ) & & strcmp ( np - > name , " ATA " ) & &
strcmp ( np - > type , " ide " ) & & strcmp ( np - > type , " ata " ) ) ) {
2005-12-13 10:01:21 +03:00
if ( index = = 0 & & ( res - > end - res - > start ) > 0xfff )
2005-04-17 02:20:36 +04:00
res - > end = res - > start + 0xfff ;
2005-12-13 10:01:21 +03:00
if ( index = = 1 & & ( res - > end - res - > start ) > 0xff )
2005-04-17 02:20:36 +04:00
res - > end = res - > start + 0xff ;
}
}
return 0 ;
}
2005-11-23 09:59:04 +03:00
static void macio_setup_interrupts ( struct macio_dev * dev )
{
struct device_node * np = dev - > ofdev . node ;
int i , j ;
/* For now, we use pre-parsed entries in the device-tree for
* interrupt routing and addresses , but we should change that
* to dynamically parsed entries and so get rid of most of the
* clutter in struct device_node
*/
for ( i = j = 0 ; i < np - > n_intrs ; i + + ) {
struct resource * res = & dev - > interrupt [ j ] ;
if ( j > = MACIO_DEV_COUNT_IRQS )
break ;
res - > start = np - > intrs [ i ] . line ;
res - > flags = IORESOURCE_IO ;
if ( np - > intrs [ j ] . sense )
res - > flags | = IORESOURCE_IRQ_LOWLEVEL ;
else
res - > flags | = IORESOURCE_IRQ_HIGHEDGE ;
res - > name = dev - > ofdev . dev . bus_id ;
if ( macio_resource_quirks ( np , res , i ) )
memset ( res , 0 , sizeof ( struct resource ) ) ;
else
j + + ;
}
dev - > n_interrupts = j ;
}
static void macio_setup_resources ( struct macio_dev * dev ,
struct resource * parent_res )
{
struct device_node * np = dev - > ofdev . node ;
2005-11-30 08:57:28 +03:00
struct resource r ;
2005-11-23 09:59:04 +03:00
int index ;
2005-11-30 08:57:28 +03:00
for ( index = 0 ; of_address_to_resource ( np , index , & r ) = = 0 ; index + + ) {
2005-11-23 09:59:04 +03:00
struct resource * res = & dev - > resource [ index ] ;
if ( index > = MACIO_DEV_COUNT_RESOURCES )
break ;
2005-11-30 08:57:28 +03:00
* res = r ;
2005-11-23 09:59:04 +03:00
res - > name = dev - > ofdev . dev . bus_id ;
if ( macio_resource_quirks ( np , res , index ) ) {
memset ( res , 0 , sizeof ( struct resource ) ) ;
continue ;
}
/* Currently, we consider failure as harmless, this may
* change in the future , once I ' ve found all the device
* tree bugs in older machines & worked around them
2005-12-13 10:01:21 +03:00
*/
2005-11-23 09:59:04 +03:00
if ( insert_resource ( parent_res , res ) ) {
printk ( KERN_WARNING " Can't request resource "
" %d for MacIO device %s \n " ,
index , dev - > ofdev . dev . bus_id ) ;
}
}
dev - > n_resources = index ;
}
2005-04-17 02:20:36 +04:00
/**
* macio_add_one_device - Add one device from OF node to the device tree
* @ chip : pointer to the macio_chip holding the device
* @ np : pointer to the device node in the OF tree
* @ in_bay : set to 1 if device is part of a media - bay
*
* When media - bay is changed to hotswap drivers , this function will
* be exposed to the bay driver some way . . .
*/
2005-11-23 09:59:04 +03:00
static struct macio_dev * macio_add_one_device ( struct macio_chip * chip ,
struct device * parent ,
struct device_node * np ,
struct macio_dev * in_bay ,
2005-04-17 02:20:36 +04:00
struct resource * parent_res )
{
struct macio_dev * dev ;
u32 * reg ;
if ( np = = NULL )
return NULL ;
dev = kmalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
if ( ! dev )
return NULL ;
memset ( dev , 0 , sizeof ( * dev ) ) ;
dev - > bus = & chip - > lbus ;
dev - > media_bay = in_bay ;
dev - > ofdev . node = np ;
dev - > ofdev . dma_mask = 0xffffffffUL ;
dev - > ofdev . dev . dma_mask = & dev - > ofdev . dma_mask ;
dev - > ofdev . dev . parent = parent ;
dev - > ofdev . dev . bus = & macio_bus_type ;
dev - > ofdev . dev . release = macio_release_dev ;
# ifdef DEBUG
printk ( " preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p \n " ,
dev , & dev - > ofdev , & dev - > ofdev . dev , & dev - > ofdev . dev . kobj ) ;
# endif
/* MacIO itself has a different reg, we use it's PCI base */
if ( np = = chip - > of_node ) {
2005-11-23 09:59:04 +03:00
sprintf ( dev - > ofdev . dev . bus_id , " %1d.%08lx:%.*s " ,
chip - > lbus . index ,
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PCI
pci_resource_start ( chip - > lbus . pdev , 0 ) ,
# else
0 , /* NuBus may want to do something better here */
# endif
MAX_NODE_NAME_SIZE , np - > name ) ;
} else {
reg = ( u32 * ) get_property ( np , " reg " , NULL ) ;
2005-11-23 09:59:04 +03:00
sprintf ( dev - > ofdev . dev . bus_id , " %1d.%08x:%.*s " ,
chip - > lbus . index ,
2005-04-17 02:20:36 +04:00
reg ? * reg : 0 , MAX_NODE_NAME_SIZE , np - > name ) ;
}
2005-11-23 09:59:04 +03:00
/* Setup interrupts & resources */
macio_setup_interrupts ( dev ) ;
macio_setup_resources ( dev , parent_res ) ;
2005-04-17 02:20:36 +04:00
2005-11-23 09:59:04 +03:00
/* Register with core */
2005-04-17 02:20:36 +04:00
if ( of_device_register ( & dev - > ofdev ) ! = 0 ) {
printk ( KERN_DEBUG " macio: device registration error for %s! \n " ,
dev - > ofdev . dev . bus_id ) ;
kfree ( dev ) ;
return NULL ;
}
return dev ;
}
static int macio_skip_device ( struct device_node * np )
{
if ( strncmp ( np - > name , " battery " , 7 ) = = 0 )
return 1 ;
if ( strncmp ( np - > name , " escc-legacy " , 11 ) = = 0 )
return 1 ;
return 0 ;
}
/**
* macio_pci_add_devices - Adds sub - devices of mac - io to the device tree
* @ chip : pointer to the macio_chip holding the devices
*
* This function will do the job of extracting devices from the
* Open Firmware device tree , build macio_dev structures and add
* them to the Linux device tree .
*
* For now , childs of media - bay are added now as well . This will
* change rsn though .
*/
static void macio_pci_add_devices ( struct macio_chip * chip )
{
struct device_node * np , * pnode ;
struct macio_dev * rdev , * mdev , * mbdev = NULL , * sdev = NULL ;
struct device * parent = NULL ;
struct resource * root_res = & iomem_resource ;
/* Add a node for the macio bus itself */
# ifdef CONFIG_PCI
if ( chip - > lbus . pdev ) {
parent = & chip - > lbus . pdev - > dev ;
root_res = & chip - > lbus . pdev - > resource [ 0 ] ;
}
# endif
pnode = of_node_get ( chip - > of_node ) ;
if ( pnode = = NULL )
return ;
/* Add macio itself to hierarchy */
rdev = macio_add_one_device ( chip , parent , pnode , NULL , root_res ) ;
if ( rdev = = NULL )
return ;
root_res = & rdev - > resource [ 0 ] ;
/* First scan 1st level */
for ( np = NULL ; ( np = of_get_next_child ( pnode , np ) ) ! = NULL ; ) {
2005-11-23 09:59:04 +03:00
if ( macio_skip_device ( np ) )
continue ;
of_node_get ( np ) ;
mdev = macio_add_one_device ( chip , & rdev - > ofdev . dev , np , NULL ,
root_res ) ;
if ( mdev = = NULL )
of_node_put ( np ) ;
else if ( strncmp ( np - > name , " media-bay " , 9 ) = = 0 )
mbdev = mdev ;
else if ( strncmp ( np - > name , " escc " , 4 ) = = 0 )
sdev = mdev ;
2005-04-17 02:20:36 +04:00
}
/* Add media bay devices if any */
if ( mbdev )
2005-11-23 09:59:04 +03:00
for ( np = NULL ; ( np = of_get_next_child ( mbdev - > ofdev . node , np ) )
! = NULL ; ) {
if ( macio_skip_device ( np ) )
continue ;
of_node_get ( np ) ;
if ( macio_add_one_device ( chip , & mbdev - > ofdev . dev , np ,
mbdev , root_res ) = = NULL )
of_node_put ( np ) ;
}
2005-04-17 02:20:36 +04:00
/* Add serial ports if any */
if ( sdev ) {
2005-11-23 09:59:04 +03:00
for ( np = NULL ; ( np = of_get_next_child ( sdev - > ofdev . node , np ) )
! = NULL ; ) {
if ( macio_skip_device ( np ) )
continue ;
of_node_get ( np ) ;
if ( macio_add_one_device ( chip , & sdev - > ofdev . dev , np ,
NULL , root_res ) = = NULL )
of_node_put ( np ) ;
}
2005-04-17 02:20:36 +04:00
}
}
/**
* macio_register_driver - Registers a new MacIO device driver
* @ drv : pointer to the driver definition structure
*/
int macio_register_driver ( struct macio_driver * drv )
{
/* initialize common driver fields */
drv - > driver . name = drv - > name ;
drv - > driver . bus = & macio_bus_type ;
/* register with core */
2006-03-22 10:20:28 +03:00
return driver_register ( & drv - > driver ) ;
2005-04-17 02:20:36 +04:00
}
/**
* macio_unregister_driver - Unregisters a new MacIO device driver
* @ drv : pointer to the driver definition structure
*/
void macio_unregister_driver ( struct macio_driver * drv )
{
driver_unregister ( & drv - > driver ) ;
}
/**
* macio_request_resource - Request an MMIO resource
* @ dev : pointer to the device holding the resource
* @ resource_no : resource number to request
* @ name : resource name
*
* Mark memory region number @ resource_no associated with MacIO
* device @ dev as being reserved by owner @ name . Do not access
* any address inside the memory regions unless this call returns
* successfully .
*
* Returns 0 on success , or % EBUSY on error . A warning
* message is also printed on failure .
*/
2005-11-23 09:59:04 +03:00
int macio_request_resource ( struct macio_dev * dev , int resource_no ,
const char * name )
2005-04-17 02:20:36 +04:00
{
if ( macio_resource_len ( dev , resource_no ) = = 0 )
return 0 ;
if ( ! request_mem_region ( macio_resource_start ( dev , resource_no ) ,
macio_resource_len ( dev , resource_no ) ,
name ) )
goto err_out ;
return 0 ;
err_out :
printk ( KERN_WARNING " MacIO: Unable to reserve resource #%d:%lx@%lx "
" for device %s \n " ,
resource_no ,
macio_resource_len ( dev , resource_no ) ,
macio_resource_start ( dev , resource_no ) ,
dev - > ofdev . dev . bus_id ) ;
return - EBUSY ;
}
/**
* macio_release_resource - Release an MMIO resource
* @ dev : pointer to the device holding the resource
* @ resource_no : resource number to release
*/
void macio_release_resource ( struct macio_dev * dev , int resource_no )
{
if ( macio_resource_len ( dev , resource_no ) = = 0 )
return ;
release_mem_region ( macio_resource_start ( dev , resource_no ) ,
macio_resource_len ( dev , resource_no ) ) ;
}
/**
* macio_request_resources - Reserve all memory resources
* @ dev : MacIO device whose resources are to be reserved
* @ name : Name to be associated with resource .
*
* Mark all memory regions associated with MacIO device @ dev as
* being reserved by owner @ name . Do not access any address inside
* the memory regions unless this call returns successfully .
*
* Returns 0 on success , or % EBUSY on error . A warning
* message is also printed on failure .
*/
int macio_request_resources ( struct macio_dev * dev , const char * name )
{
int i ;
for ( i = 0 ; i < dev - > n_resources ; i + + )
if ( macio_request_resource ( dev , i , name ) )
goto err_out ;
return 0 ;
err_out :
while ( - - i > = 0 )
macio_release_resource ( dev , i ) ;
return - EBUSY ;
}
/**
* macio_release_resources - Release reserved memory resources
* @ dev : MacIO device whose resources were previously reserved
*/
void macio_release_resources ( struct macio_dev * dev )
{
int i ;
for ( i = 0 ; i < dev - > n_resources ; i + + )
macio_release_resource ( dev , i ) ;
}
# ifdef CONFIG_PCI
static int __devinit macio_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
struct device_node * np ;
struct macio_chip * chip ;
if ( ent - > vendor ! = PCI_VENDOR_ID_APPLE )
return - ENODEV ;
2005-11-23 09:59:04 +03:00
/* Note regarding refcounting: We assume pci_device_to_OF_node() is
* ported to new OF APIs and returns a node with refcount incremented .
2005-04-17 02:20:36 +04:00
*/
np = pci_device_to_OF_node ( pdev ) ;
if ( np = = NULL )
return - ENODEV ;
2005-11-23 09:59:04 +03:00
/* The above assumption is wrong !!!
* fix that here for now until I fix the arch code
*/
2005-04-17 02:20:36 +04:00
of_node_get ( np ) ;
2005-11-23 09:59:04 +03:00
/* We also assume that pmac_feature will have done a get() on nodes
* stored in the macio chips array
2005-04-17 02:20:36 +04:00
*/
chip = macio_find ( np , macio_unknown ) ;
of_node_put ( np ) ;
if ( chip = = NULL )
return - ENODEV ;
/* XXX Need locking ??? */
if ( chip - > lbus . pdev = = NULL ) {
chip - > lbus . pdev = pdev ;
chip - > lbus . chip = chip ;
pci_set_drvdata ( pdev , & chip - > lbus ) ;
pci_set_master ( pdev ) ;
}
printk ( KERN_INFO " MacIO PCI driver attached to %s chipset \n " ,
chip - > name ) ;
/*
* HACK ALERT : The WallStreet PowerBook and some OHare based machines
2005-11-23 09:59:04 +03:00
* have 2 macio ASICs . I must probe the " main " one first or IDE
* ordering will be incorrect . So I put on " hold " the second one since
* it seem to appear first on PCI
2005-04-17 02:20:36 +04:00
*/
if ( chip - > type = = macio_gatwick | | chip - > type = = macio_ohareII )
if ( macio_chips [ 0 ] . lbus . pdev = = NULL ) {
macio_on_hold = chip ;
return 0 ;
}
macio_pci_add_devices ( chip ) ;
if ( macio_on_hold & & macio_chips [ 0 ] . lbus . pdev ! = NULL ) {
macio_pci_add_devices ( macio_on_hold ) ;
macio_on_hold = NULL ;
}
return 0 ;
}
static void __devexit macio_pci_remove ( struct pci_dev * pdev )
{
panic ( " removing of macio-asic not supported ! \n " ) ;
}
/*
* MacIO is matched against any Apple ID , it ' s probe ( ) function
* will then decide wether it applies or not
*/
static const struct pci_device_id __devinitdata pci_ids [ ] = { {
. vendor = PCI_VENDOR_ID_APPLE ,
. device = PCI_ANY_ID ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} , { /* end: all zeroes */ }
} ;
MODULE_DEVICE_TABLE ( pci , pci_ids ) ;
/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver macio_pci_driver = {
. name = ( char * ) " macio " ,
. id_table = pci_ids ,
. probe = macio_pci_probe ,
. remove = macio_pci_remove ,
} ;
# endif /* CONFIG_PCI */
static int __init macio_module_init ( void )
{
# ifdef CONFIG_PCI
int rc ;
rc = pci_register_driver ( & macio_pci_driver ) ;
if ( rc )
return rc ;
# endif /* CONFIG_PCI */
return 0 ;
}
module_init ( macio_module_init ) ;
EXPORT_SYMBOL ( macio_register_driver ) ;
EXPORT_SYMBOL ( macio_unregister_driver ) ;
EXPORT_SYMBOL ( macio_dev_get ) ;
EXPORT_SYMBOL ( macio_dev_put ) ;
EXPORT_SYMBOL ( macio_request_resource ) ;
EXPORT_SYMBOL ( macio_release_resource ) ;
EXPORT_SYMBOL ( macio_request_resources ) ;
EXPORT_SYMBOL ( macio_release_resources ) ;