162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  DIO Driver Services
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 2004 Jochen Friedrich
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Loosely based on drivers/pci/pci-driver.c and drivers/zorro/zorro-driver.c
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  This file is subject to the terms and conditions of the GNU General Public
962306a36Sopenharmony_ci *  License.  See the file COPYING in the main directory of this archive
1062306a36Sopenharmony_ci *  for more details.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/dio.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/**
1962306a36Sopenharmony_ci *  dio_match_device - Tell if a DIO device structure has a matching DIO device id structure
2062306a36Sopenharmony_ci *  @ids: array of DIO device id structures to search in
2162306a36Sopenharmony_ci *  @d: the DIO device structure to match against
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *  Used by a driver to check whether a DIO device present in the
2462306a36Sopenharmony_ci *  system is in its list of supported devices. Returns the matching
2562306a36Sopenharmony_ci *  dio_device_id structure or %NULL if there is no match.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic const struct dio_device_id *
2962306a36Sopenharmony_cidio_match_device(const struct dio_device_id *ids,
3062306a36Sopenharmony_ci		   const struct dio_dev *d)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	while (ids->id) {
3362306a36Sopenharmony_ci		if (ids->id == DIO_WILDCARD)
3462306a36Sopenharmony_ci			return ids;
3562306a36Sopenharmony_ci		if (DIO_NEEDSSECID(ids->id & 0xff)) {
3662306a36Sopenharmony_ci			if (ids->id == d->id)
3762306a36Sopenharmony_ci				return ids;
3862306a36Sopenharmony_ci		} else {
3962306a36Sopenharmony_ci			if ((ids->id & 0xff) == (d->id & 0xff))
4062306a36Sopenharmony_ci				return ids;
4162306a36Sopenharmony_ci		}
4262306a36Sopenharmony_ci		ids++;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci	return NULL;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int dio_device_probe(struct device *dev)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	int error = 0;
5062306a36Sopenharmony_ci	struct dio_driver *drv = to_dio_driver(dev->driver);
5162306a36Sopenharmony_ci	struct dio_dev *d = to_dio_dev(dev);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (!d->driver && drv->probe) {
5462306a36Sopenharmony_ci		const struct dio_device_id *id;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci		id = dio_match_device(drv->id_table, d);
5762306a36Sopenharmony_ci		if (id)
5862306a36Sopenharmony_ci			error = drv->probe(d, id);
5962306a36Sopenharmony_ci		if (error >= 0) {
6062306a36Sopenharmony_ci			d->driver = drv;
6162306a36Sopenharmony_ci			error = 0;
6262306a36Sopenharmony_ci		}
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci	return error;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/**
6962306a36Sopenharmony_ci *  dio_register_driver - register a new DIO driver
7062306a36Sopenharmony_ci *  @drv: the driver structure to register
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci *  Adds the driver structure to the list of registered drivers
7362306a36Sopenharmony_ci *  Returns zero or a negative error value.
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ciint dio_register_driver(struct dio_driver *drv)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	/* initialize common driver fields */
7962306a36Sopenharmony_ci	drv->driver.name = drv->name;
8062306a36Sopenharmony_ci	drv->driver.bus = &dio_bus_type;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* register with core */
8362306a36Sopenharmony_ci	return driver_register(&drv->driver);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/**
8862306a36Sopenharmony_ci *  dio_unregister_driver - unregister a DIO driver
8962306a36Sopenharmony_ci *  @drv: the driver structure to unregister
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci *  Deletes the driver structure from the list of registered DIO drivers,
9262306a36Sopenharmony_ci *  gives it a chance to clean up by calling its remove() function for
9362306a36Sopenharmony_ci *  each device it was responsible for, and marks those devices as
9462306a36Sopenharmony_ci *  driverless.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_civoid dio_unregister_driver(struct dio_driver *drv)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	driver_unregister(&drv->driver);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/**
10462306a36Sopenharmony_ci *  dio_bus_match - Tell if a DIO device structure has a matching DIO device id structure
10562306a36Sopenharmony_ci *  @dev: the DIO device structure to match against
10662306a36Sopenharmony_ci *  @drv: the &device_driver that points to the array of DIO device id structures to search
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci *  Used by the driver core to check whether a DIO device present in the
10962306a36Sopenharmony_ci *  system is in a driver's list of supported devices. Returns 1 if supported,
11062306a36Sopenharmony_ci *  and 0 if there is no match.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic int dio_bus_match(struct device *dev, struct device_driver *drv)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct dio_dev *d = to_dio_dev(dev);
11662306a36Sopenharmony_ci	struct dio_driver *dio_drv = to_dio_driver(drv);
11762306a36Sopenharmony_ci	const struct dio_device_id *ids = dio_drv->id_table;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (!ids)
12062306a36Sopenharmony_ci		return 0;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return dio_match_device(ids, d) ? 1 : 0;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistruct bus_type dio_bus_type = {
12762306a36Sopenharmony_ci	.name	= "dio",
12862306a36Sopenharmony_ci	.match	= dio_bus_match,
12962306a36Sopenharmony_ci	.probe	= dio_device_probe,
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int __init dio_driver_init(void)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	return bus_register(&dio_bus_type);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cipostcore_initcall(dio_driver_init);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciEXPORT_SYMBOL(dio_register_driver);
14162306a36Sopenharmony_ciEXPORT_SYMBOL(dio_unregister_driver);
14262306a36Sopenharmony_ciEXPORT_SYMBOL(dio_bus_type);
143