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