11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.com> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2 of the License, or (at your 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * option) any later version. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes/additions: 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Markus Lidel <Markus.Lidel@shadowconnect.com> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * initial version. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rwsem.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2o.h> 204e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/workqueue.h> 214e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/string.h> 224e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/slab.h> 239e87545f06930c1d294423a8091d1077e7444a47Markus Lidel#include "core.h" 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel#define OSM_NAME "i2o" 2661fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */ 289e87545f06930c1d294423a8091d1077e7444a47Markus Lidelstatic unsigned int i2o_max_drivers = I2O_MAX_DRIVERS; 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(max_drivers, i2o_max_drivers, uint, 0); 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support"); 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I2O drivers lock and array */ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic spinlock_t i2o_drivers_lock; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_driver **i2o_drivers; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 37d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * i2o_bus_match - Tell if I2O device class id matches the class ids of the I2O driver (OSM) 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: device which should be verified 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: the driver to match against 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used by the bus to check if the driver wants to handle the device. 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 1 if the class ids of the driver match the class id of the 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device, otherwise 0. 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_bus_match(struct device *dev, struct device_driver *drv) 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *i2o_dev = to_i2o_device(dev); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_driver *i2o_drv = to_i2o_driver(drv); 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_class_id *ids = i2o_drv->classes; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ids) 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (ids->class_id != I2O_CLASS_END) { 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ids->class_id == i2o_dev->lct_data.class_id) 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ids++; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I2O bus type */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct bus_type i2o_bus_type = { 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "i2o", 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .match = i2o_bus_match, 652e1973a3cd0b9fe31469be62df3583bdc5a34f51Markus Lidel .dev_attrs = i2o_device_attrs 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_driver_register - Register a I2O driver (OSM) in the I2O core 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: I2O driver which should be registered 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Registers the OSM drv in the I2O core and creates an event queues if 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * necessary. 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 on success or negative error code on failure. 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint i2o_driver_register(struct i2o_driver *drv) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_controller *c; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_debug("Register driver %s\n", drv->name); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (drv->event) { 8752286713a9ae1c4c80d521a8990e8c3ba14118f3Tejun Heo drv->event_queue = alloc_workqueue(drv->name, 8852286713a9ae1c4c80d521a8990e8c3ba14118f3Tejun Heo WQ_MEM_RECLAIM, 1); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!drv->event_queue) { 90f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_err("Could not initialize event queue for driver " 91f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel "%s\n", drv->name); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 94f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_debug("Event queue initialized for driver %s\n", drv->name); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->event_queue = NULL; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->driver.name = drv->name; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->driver.bus = &i2o_bus_type; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&i2o_drivers_lock, flags); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i2o_drivers[i]; i++) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i >= i2o_max_drivers) { 105f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_err("too many drivers registered, increase " 106f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel "max_drivers\n"); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&i2o_drivers_lock, flags); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->context = i; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_drivers[i] = drv; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&i2o_drivers_lock, flags); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 116f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_debug("driver %s gets context id %d\n", drv->name, drv->context); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(c, &i2o_controllers, list) { 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *i2o_dev; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_driver_notify_controller_add(drv, c); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(i2o_dev, &c->devices, list) 123f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidel i2o_driver_notify_device_add(drv, i2o_dev); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = driver_register(&drv->driver); 127e578e9a1cc8a5983d87126d5877e305d3189f1b9Akinobu Mita if (rc) { 128e578e9a1cc8a5983d87126d5877e305d3189f1b9Akinobu Mita if (drv->event) { 129e578e9a1cc8a5983d87126d5877e305d3189f1b9Akinobu Mita destroy_workqueue(drv->event_queue); 130e578e9a1cc8a5983d87126d5877e305d3189f1b9Akinobu Mita drv->event_queue = NULL; 131e578e9a1cc8a5983d87126d5877e305d3189f1b9Akinobu Mita } 132e578e9a1cc8a5983d87126d5877e305d3189f1b9Akinobu Mita } 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @drv: I2O driver which should be unregistered 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unregisters the OSM drv from the I2O core and cleanup event queues if 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * necessary. 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid i2o_driver_unregister(struct i2o_driver *drv) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_controller *c; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 149f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_debug("unregister driver %s\n", drv->name); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver_unregister(&drv->driver); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(c, &i2o_controllers, list) { 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_device *i2o_dev; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(i2o_dev, &c->devices, list) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_driver_notify_device_remove(drv, i2o_dev); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_driver_notify_controller_remove(drv, c); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&i2o_drivers_lock, flags); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_drivers[drv->context] = NULL; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&i2o_drivers_lock, flags); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (drv->event_queue) { 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds destroy_workqueue(drv->event_queue); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv->event_queue = NULL; 169f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_debug("event queue removed for %s\n", drv->name); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_driver_dispatch - dispatch an I2O reply message 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @c: I2O controller of the message 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @m: I2O message number 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The reply is delivered to the driver from which the original message 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * was. This function is only called from interrupt context. 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 on success and the message should not be flushed. Returns > 0 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on success and if the message should be flushed afterwords. Returns 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negative error code on failure (the message will be flushed too). 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 185f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidelint i2o_driver_dispatch(struct i2o_controller *c, u32 m) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_driver *drv; 1889e87545f06930c1d294423a8091d1077e7444a47Markus Lidel struct i2o_message *msg = i2o_msg_out_to_virt(c, m); 1899e87545f06930c1d294423a8091d1077e7444a47Markus Lidel u32 context = le32_to_cpu(msg->u.s.icntxt); 190f10378fff658f61307496e0ae00095041725cf07Markus Lidel unsigned long flags; 191f10378fff658f61307496e0ae00095041725cf07Markus Lidel 19261fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel if (unlikely(context >= i2o_max_drivers)) { 193f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_warn("%s: Spurious reply to unknown driver %d\n", c->name, 194f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel context); 19561fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel return -EIO; 19661fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel } 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 198f10378fff658f61307496e0ae00095041725cf07Markus Lidel spin_lock_irqsave(&i2o_drivers_lock, flags); 19961fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel drv = i2o_drivers[context]; 200f10378fff658f61307496e0ae00095041725cf07Markus Lidel spin_unlock_irqrestore(&i2o_drivers_lock, flags); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20261fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel if (unlikely(!drv)) { 203f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_warn("%s: Spurious reply to unknown driver %d\n", c->name, 204f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel context); 20561fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel return -EIO; 20661fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2089e87545f06930c1d294423a8091d1077e7444a47Markus Lidel if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) { 20961fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel struct i2o_device *dev, *tmp; 21061fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel struct i2o_event *evt; 21161fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel u16 size; 2129e87545f06930c1d294423a8091d1077e7444a47Markus Lidel u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21461fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel osm_debug("event received from device %d\n", tid); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 216f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel if (!drv->event) 217f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel return -EIO; 218f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel 21961fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel /* cut of header from message size (in 32-bit words) */ 2209e87545f06930c1d294423a8091d1077e7444a47Markus Lidel size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 222f6ed39a6e1a88240eec629a3da17c3a47ada3b89Markus Lidel evt = kzalloc(size * 4 + sizeof(*evt), GFP_ATOMIC); 22361fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel if (!evt) 22461fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel return -ENOMEM; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22661fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel evt->size = size; 2279e87545f06930c1d294423a8091d1077e7444a47Markus Lidel evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt); 2289e87545f06930c1d294423a8091d1077e7444a47Markus Lidel evt->event_indicator = le32_to_cpu(msg->body[0]); 229dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel memcpy(&evt->data, &msg->body[1], size * 4); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23161fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel list_for_each_entry_safe(dev, tmp, &c->devices, list) 23261fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel if (dev->lct_data.tid == tid) { 23361fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel evt->i2o_dev = dev; 23461fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel break; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 237c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_WORK(&evt->work, drv->event); 23861fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel queue_work(drv->event_queue, &evt->work); 23961fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel return 1; 24061fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel } 24161fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel 24261fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel if (unlikely(!drv->reply)) { 243f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_debug("%s: Reply to driver %s, but no reply function" 244f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel " defined!\n", c->name, drv->name); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 24661fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel } 24761fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel 24861fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel return drv->reply(c, m, msg); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_driver_notify_controller_add_all - Send notify of added controller 253d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * @c: newly added controller 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send notifications to all registered drivers that a new controller was 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * added. 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid i2o_driver_notify_controller_add_all(struct i2o_controller *c) 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_driver *drv; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 263be324797d9b2a10f767e89dfbd880c735249bef9Akinobu Mita for (i = 0; i < i2o_max_drivers; i++) { 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv = i2o_drivers[i]; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (drv) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_driver_notify_controller_add(drv, c); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 272d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * i2o_driver_notify_controller_remove_all - Send notify of removed controller 273d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * @c: controller that is being removed 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send notifications to all registered drivers that a controller was 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * removed. 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid i2o_driver_notify_controller_remove_all(struct i2o_controller *c) 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_driver *drv; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 283be324797d9b2a10f767e89dfbd880c735249bef9Akinobu Mita for (i = 0; i < i2o_max_drivers; i++) { 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv = i2o_drivers[i]; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (drv) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_driver_notify_controller_remove(drv, c); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 292d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * i2o_driver_notify_device_add_all - Send notify of added device 293d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * @i2o_dev: newly added I2O device 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send notifications to all registered drivers that a device was added. 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_driver *drv; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 302be324797d9b2a10f767e89dfbd880c735249bef9Akinobu Mita for (i = 0; i < i2o_max_drivers; i++) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv = i2o_drivers[i]; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (drv) 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_driver_notify_device_add(drv, i2o_dev); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 311d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * i2o_driver_notify_device_remove_all - Send notify of removed device 312d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * @i2o_dev: device that is being removed 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send notifications to all registered drivers that a device was removed. 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev) 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2o_driver *drv; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321be324797d9b2a10f767e89dfbd880c735249bef9Akinobu Mita for (i = 0; i < i2o_max_drivers; i++) { 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drv = i2o_drivers[i]; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (drv) 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_driver_notify_device_remove(drv, i2o_dev); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_driver_init - initialize I2O drivers (OSMs) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Registers the I2O bus and allocate memory for the array of OSMs. 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns 0 on success or negative error code on failure. 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init i2o_driver_init(void) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&i2o_drivers_lock); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34282cd0e8410ae74d3fd39d168049381eafc489e5bAkinobu Mita if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64)) { 34382cd0e8410ae74d3fd39d168049381eafc489e5bAkinobu Mita osm_warn("max_drivers set to %d, but must be >=2 and <= 64\n", 34482cd0e8410ae74d3fd39d168049381eafc489e5bAkinobu Mita i2o_max_drivers); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_max_drivers = I2O_MAX_DRIVERS; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 347f88e119c4b824a5017456fa094950d0f4092d96cMarkus Lidel osm_info("max drivers = %d\n", i2o_max_drivers); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2o_drivers = 350be324797d9b2a10f767e89dfbd880c735249bef9Akinobu Mita kcalloc(i2o_max_drivers, sizeof(*i2o_drivers), GFP_KERNEL); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i2o_drivers) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = bus_register(&i2o_bus_type); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc < 0) 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(i2o_drivers); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i2o_driver_exit - clean up I2O drivers (OSMs) 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 365d9489fb60614794cbca4b6b173c60ed9388974c6Randy Dunlap * Unregisters the I2O bus and frees driver array. 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 367d78437245aa3842e8eeaef2709753ac485465652Ralf Baechlevoid i2o_driver_exit(void) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_unregister(&i2o_bus_type); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(i2o_drivers); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(i2o_driver_register); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(i2o_driver_unregister); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(i2o_driver_notify_controller_add_all); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(i2o_driver_notify_controller_remove_all); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(i2o_driver_notify_device_add_all); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(i2o_driver_notify_device_remove_all); 379