2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-11-07 12:00:15 +03:00
/*
* RapidIO driver support
*
* Copyright 2005 MontaVista Software , Inc .
* Matt Porter < mporter @ kernel . crashing . org >
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/rio.h>
# include <linux/rio_ids.h>
# include "rio.h"
/**
* rio_match_device - Tell if a RIO device has a matching RIO device id structure
* @ id : the RIO device id structure to match against
* @ rdev : the RIO device structure to match against
*
* Used from driver probe and bus matching to check whether a RIO device
* matches a device id structure provided by a RIO driver . Returns the
* matching & struct rio_device_id or % NULL if there is no match .
*/
static const struct rio_device_id * rio_match_device ( const struct rio_device_id
* id ,
const struct rio_dev * rdev )
{
while ( id - > vid | | id - > asm_vid ) {
if ( ( ( id - > vid = = RIO_ANY_ID ) | | ( id - > vid = = rdev - > vid ) ) & &
( ( id - > did = = RIO_ANY_ID ) | | ( id - > did = = rdev - > did ) ) & &
( ( id - > asm_vid = = RIO_ANY_ID )
| | ( id - > asm_vid = = rdev - > asm_vid ) )
& & ( ( id - > asm_did = = RIO_ANY_ID )
| | ( id - > asm_did = = rdev - > asm_did ) ) )
return id ;
id + + ;
}
return NULL ;
}
/**
* rio_dev_get - Increments the reference count of the RIO device structure
*
* @ rdev : RIO device being referenced
*
* Each live reference to a device should be refcounted .
*
* Drivers for RIO devices should normally record such references in
* their probe ( ) methods , when they bind to a device , and release
* them by calling rio_dev_put ( ) , in their disconnect ( ) methods .
*/
struct rio_dev * rio_dev_get ( struct rio_dev * rdev )
{
if ( rdev )
get_device ( & rdev - > dev ) ;
return rdev ;
}
/**
* rio_dev_put - Release a use of the RIO device structure
*
* @ rdev : RIO device being disconnected
*
* Must be called when a user of a device is finished with it .
* When the last user of the device calls this function , the
* memory of the device is freed .
*/
void rio_dev_put ( struct rio_dev * rdev )
{
if ( rdev )
put_device ( & rdev - > dev ) ;
}
/**
2008-03-01 09:02:40 +03:00
* rio_device_probe - Tell if a RIO device structure has a matching RIO device id structure
2005-11-07 12:00:15 +03:00
* @ dev : the RIO device structure to match against
*
* return 0 and set rio_dev - > driver when drv claims rio_dev , else error
*/
static int rio_device_probe ( struct device * dev )
{
struct rio_driver * rdrv = to_rio_driver ( dev - > driver ) ;
struct rio_dev * rdev = to_rio_dev ( dev ) ;
int error = - ENODEV ;
const struct rio_device_id * id ;
if ( ! rdev - > driver & & rdrv - > probe ) {
if ( ! rdrv - > id_table )
return error ;
id = rio_match_device ( rdrv - > id_table , rdev ) ;
rio_dev_get ( rdev ) ;
if ( id )
error = rdrv - > probe ( rdev , id ) ;
if ( error > = 0 ) {
rdev - > driver = rdrv ;
error = 0 ;
2008-07-11 04:30:44 +04:00
} else
2005-11-07 12:00:15 +03:00
rio_dev_put ( rdev ) ;
}
return error ;
}
/**
* rio_device_remove - Remove a RIO device from the system
*
* @ dev : the RIO device structure to match against
*
* Remove a RIO device from the system . If it has an associated
* driver , then run the driver remove ( ) method . Then update
* the reference count .
*/
static int rio_device_remove ( struct device * dev )
{
struct rio_dev * rdev = to_rio_dev ( dev ) ;
struct rio_driver * rdrv = rdev - > driver ;
if ( rdrv ) {
if ( rdrv - > remove )
rdrv - > remove ( rdev ) ;
rdev - > driver = NULL ;
}
rio_dev_put ( rdev ) ;
return 0 ;
}
2016-03-23 00:26:05 +03:00
static void rio_device_shutdown ( struct device * dev )
{
struct rio_dev * rdev = to_rio_dev ( dev ) ;
struct rio_driver * rdrv = rdev - > driver ;
dev_dbg ( dev , " RIO: %s \n " , __func__ ) ;
if ( rdrv & & rdrv - > shutdown )
rdrv - > shutdown ( rdev ) ;
}
2005-11-07 12:00:15 +03:00
/**
* rio_register_driver - register a new RIO driver
* @ rdrv : the RIO driver structure to register
*
2008-03-01 09:02:40 +03:00
* Adds a & struct rio_driver to the list of registered drivers .
2005-11-07 12:00:15 +03:00
* Returns a negative value on error , otherwise 0. If no error
* occurred , the driver remains registered even if no device
* was claimed during registration .
*/
int rio_register_driver ( struct rio_driver * rdrv )
{
/* initialize common driver fields */
rdrv - > driver . name = rdrv - > name ;
rdrv - > driver . bus = & rio_bus_type ;
/* register with core */
return driver_register ( & rdrv - > driver ) ;
}
/**
* rio_unregister_driver - unregister a RIO driver
* @ rdrv : the RIO driver structure to unregister
*
* Deletes the & struct rio_driver from the list of registered RIO
* drivers , gives it a chance to clean up by calling its remove ( )
* function for each device it was responsible for , and marks those
* devices as driverless .
*/
void rio_unregister_driver ( struct rio_driver * rdrv )
{
driver_unregister ( & rdrv - > driver ) ;
}
2013-05-25 02:55:05 +04:00
void rio_attach_device ( struct rio_dev * rdev )
{
rdev - > dev . bus = & rio_bus_type ;
}
EXPORT_SYMBOL_GPL ( rio_attach_device ) ;
2005-11-07 12:00:15 +03:00
/**
2008-03-01 09:02:40 +03:00
* rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure
2005-11-07 12:00:15 +03:00
* @ dev : the standard device structure to match against
* @ drv : the standard driver structure containing the ids to match against
*
* Used by a driver to check whether a RIO device present in the
* system is in its list of supported devices . Returns 1 if
* there is a matching & struct rio_device_id or 0 if there is
* no match .
*/
static int rio_match_bus ( struct device * dev , struct device_driver * drv )
{
struct rio_dev * rdev = to_rio_dev ( dev ) ;
struct rio_driver * rdrv = to_rio_driver ( drv ) ;
const struct rio_device_id * id = rdrv - > id_table ;
const struct rio_device_id * found_id ;
if ( ! id )
goto out ;
found_id = rio_match_device ( id , rdev ) ;
if ( found_id )
return 1 ;
out : return 0 ;
}
2013-07-04 02:08:58 +04:00
static int rio_uevent ( struct device * dev , struct kobj_uevent_env * env )
{
struct rio_dev * rdev ;
if ( ! dev )
return - ENODEV ;
rdev = to_rio_dev ( dev ) ;
if ( ! rdev )
return - ENODEV ;
if ( add_uevent_var ( env , " MODALIAS=rapidio:v%04Xd%04Xav%04Xad%04X " ,
rdev - > vid , rdev - > did , rdev - > asm_vid , rdev - > asm_did ) )
return - ENOMEM ;
return 0 ;
}
2014-04-08 02:38:56 +04:00
struct class rio_mport_class = {
. name = " rapidio_port " ,
. owner = THIS_MODULE ,
. dev_groups = rio_mport_groups ,
2005-11-07 12:00:15 +03:00
} ;
2014-04-08 02:38:56 +04:00
EXPORT_SYMBOL_GPL ( rio_mport_class ) ;
2005-11-07 12:00:15 +03:00
struct bus_type rio_bus_type = {
. name = " rapidio " ,
. match = rio_match_bus ,
2013-10-07 10:55:47 +04:00
. dev_groups = rio_dev_groups ,
2013-08-24 01:24:29 +04:00
. bus_groups = rio_bus_groups ,
2006-01-05 17:44:14 +03:00
. probe = rio_device_probe ,
. remove = rio_device_remove ,
2016-03-23 00:26:05 +03:00
. shutdown = rio_device_shutdown ,
2013-07-04 02:08:58 +04:00
. uevent = rio_uevent ,
2005-11-07 12:00:15 +03:00
} ;
/**
* rio_bus_init - Register the RapidIO bus with the device model
*
2014-04-08 02:38:56 +04:00
* Registers the RIO mport device class and RIO bus type with the Linux
2005-11-07 12:00:15 +03:00
* device model .
*/
static int __init rio_bus_init ( void )
{
2014-04-08 02:38:56 +04:00
int ret ;
ret = class_register ( & rio_mport_class ) ;
if ( ! ret ) {
ret = bus_register ( & rio_bus_type ) ;
if ( ret )
class_unregister ( & rio_mport_class ) ;
}
return ret ;
2005-11-07 12:00:15 +03:00
}
postcore_initcall ( rio_bus_init ) ;
EXPORT_SYMBOL_GPL ( rio_register_driver ) ;
EXPORT_SYMBOL_GPL ( rio_unregister_driver ) ;
EXPORT_SYMBOL_GPL ( rio_bus_type ) ;
EXPORT_SYMBOL_GPL ( rio_dev_get ) ;
EXPORT_SYMBOL_GPL ( rio_dev_put ) ;