forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
269 lines
6.7 KiB
269 lines
6.7 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* RapidIO driver support |
|
* |
|
* Copyright 2005 MontaVista Software, Inc. |
|
* Matt Porter <[email protected]> |
|
*/ |
|
|
|
#include <linux/init.h> |
|
#include <linux/module.h> |
|
#include <linux/rio.h> |
|
#include <linux/rio_ids.h> |
|
#include <linux/rio_drv.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); |
|
} |
|
|
|
/** |
|
* rio_device_probe - Tell if a RIO device structure has a matching RIO device id structure |
|
* @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; |
|
} else |
|
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; |
|
} |
|
|
|
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); |
|
} |
|
|
|
/** |
|
* rio_register_driver - register a new RIO driver |
|
* @rdrv: the RIO driver structure to register |
|
* |
|
* Adds a &struct rio_driver to the list of registered drivers. |
|
* 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); |
|
} |
|
|
|
void rio_attach_device(struct rio_dev *rdev) |
|
{ |
|
rdev->dev.bus = &rio_bus_type; |
|
} |
|
EXPORT_SYMBOL_GPL(rio_attach_device); |
|
|
|
/** |
|
* rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure |
|
* @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; |
|
} |
|
|
|
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; |
|
} |
|
|
|
struct class rio_mport_class = { |
|
.name = "rapidio_port", |
|
.owner = THIS_MODULE, |
|
.dev_groups = rio_mport_groups, |
|
}; |
|
EXPORT_SYMBOL_GPL(rio_mport_class); |
|
|
|
struct bus_type rio_bus_type = { |
|
.name = "rapidio", |
|
.match = rio_match_bus, |
|
.dev_groups = rio_dev_groups, |
|
.bus_groups = rio_bus_groups, |
|
.probe = rio_device_probe, |
|
.remove = rio_device_remove, |
|
.shutdown = rio_device_shutdown, |
|
.uevent = rio_uevent, |
|
}; |
|
|
|
/** |
|
* rio_bus_init - Register the RapidIO bus with the device model |
|
* |
|
* Registers the RIO mport device class and RIO bus type with the Linux |
|
* device model. |
|
*/ |
|
static int __init rio_bus_init(void) |
|
{ |
|
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; |
|
} |
|
|
|
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);
|
|
|