Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * drivers/sh/superhyway/superhyway.c
0003  *
0004  * SuperHyway Bus Driver
0005  *
0006  * Copyright (C) 2004, 2005  Paul Mundt <lethal@linux-sh.org>
0007  *
0008  * This file is subject to the terms and conditions of the GNU General Public
0009  * License.  See the file "COPYING" in the main directory of this archive
0010  * for more details.
0011  */
0012 #include <linux/kernel.h>
0013 #include <linux/device.h>
0014 #include <linux/init.h>
0015 #include <linux/module.h>
0016 #include <linux/types.h>
0017 #include <linux/list.h>
0018 #include <linux/superhyway.h>
0019 #include <linux/string.h>
0020 #include <linux/slab.h>
0021 
0022 static int superhyway_devices;
0023 
0024 static struct device superhyway_bus_device = {
0025     .init_name = "superhyway",
0026 };
0027 
0028 static void superhyway_device_release(struct device *dev)
0029 {
0030     struct superhyway_device *sdev = to_superhyway_device(dev);
0031 
0032     kfree(sdev->resource);
0033     kfree(sdev);
0034 }
0035 
0036 /**
0037  * superhyway_add_device - Add a SuperHyway module
0038  * @base: Physical address where module is mapped.
0039  * @sdev: SuperHyway device to add, or NULL to allocate a new one.
0040  * @bus: Bus where SuperHyway module resides.
0041  *
0042  * This is responsible for adding a new SuperHyway module. This sets up a new
0043  * struct superhyway_device for the module being added if @sdev == NULL.
0044  *
0045  * Devices are initially added in the order that they are scanned (from the
0046  * top-down of the memory map), and are assigned an ID based on the order that
0047  * they are added. Any manual addition of a module will thus get the ID after
0048  * the devices already discovered regardless of where it resides in memory.
0049  *
0050  * Further work can and should be done in superhyway_scan_bus(), to be sure
0051  * that any new modules are properly discovered and subsequently registered.
0052  */
0053 int superhyway_add_device(unsigned long base, struct superhyway_device *sdev,
0054               struct superhyway_bus *bus)
0055 {
0056     struct superhyway_device *dev = sdev;
0057 
0058     if (!dev) {
0059         dev = kzalloc(sizeof(struct superhyway_device), GFP_KERNEL);
0060         if (!dev)
0061             return -ENOMEM;
0062 
0063     }
0064 
0065     dev->bus = bus;
0066     superhyway_read_vcr(dev, base, &dev->vcr);
0067 
0068     if (!dev->resource) {
0069         dev->resource = kzalloc(sizeof(struct resource), GFP_KERNEL);
0070         if (!dev->resource) {
0071             kfree(dev);
0072             return -ENOMEM;
0073         }
0074 
0075         dev->resource->name = dev->name;
0076         dev->resource->start    = base;
0077         dev->resource->end  = dev->resource->start + 0x01000000;
0078     }
0079 
0080     dev->dev.parent     = &superhyway_bus_device;
0081     dev->dev.bus        = &superhyway_bus_type;
0082     dev->dev.release    = superhyway_device_release;
0083     dev->id.id      = dev->vcr.mod_id;
0084 
0085     sprintf(dev->name, "SuperHyway device %04x", dev->id.id);
0086     dev_set_name(&dev->dev, "%02x", superhyway_devices);
0087 
0088     superhyway_devices++;
0089 
0090     return device_register(&dev->dev);
0091 }
0092 
0093 int superhyway_add_devices(struct superhyway_bus *bus,
0094                struct superhyway_device **devices,
0095                int nr_devices)
0096 {
0097     int i, ret = 0;
0098 
0099     for (i = 0; i < nr_devices; i++) {
0100         struct superhyway_device *dev = devices[i];
0101         ret |= superhyway_add_device(dev->resource[0].start, dev, bus);
0102     }
0103 
0104     return ret;
0105 }
0106 
0107 static int __init superhyway_init(void)
0108 {
0109     struct superhyway_bus *bus;
0110     int ret;
0111 
0112     ret = device_register(&superhyway_bus_device);
0113     if (unlikely(ret))
0114         return ret;
0115 
0116     for (bus = superhyway_channels; bus->ops; bus++)
0117         ret |= superhyway_scan_bus(bus);
0118 
0119     return ret;
0120 }
0121 postcore_initcall(superhyway_init);
0122 
0123 static const struct superhyway_device_id *
0124 superhyway_match_id(const struct superhyway_device_id *ids,
0125             struct superhyway_device *dev)
0126 {
0127     while (ids->id) {
0128         if (ids->id == dev->id.id)
0129             return ids;
0130 
0131         ids++;
0132     }
0133 
0134     return NULL;
0135 }
0136 
0137 static int superhyway_device_probe(struct device *dev)
0138 {
0139     struct superhyway_device *shyway_dev = to_superhyway_device(dev);
0140     struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver);
0141 
0142     if (shyway_drv && shyway_drv->probe) {
0143         const struct superhyway_device_id *id;
0144 
0145         id = superhyway_match_id(shyway_drv->id_table, shyway_dev);
0146         if (id)
0147             return shyway_drv->probe(shyway_dev, id);
0148     }
0149 
0150     return -ENODEV;
0151 }
0152 
0153 static void superhyway_device_remove(struct device *dev)
0154 {
0155     struct superhyway_device *shyway_dev = to_superhyway_device(dev);
0156     struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver);
0157 
0158     if (shyway_drv->remove)
0159         shyway_drv->remove(shyway_dev);
0160 }
0161 
0162 /**
0163  * superhyway_register_driver - Register a new SuperHyway driver
0164  * @drv: SuperHyway driver to register.
0165  *
0166  * This registers the passed in @drv. Any devices matching the id table will
0167  * automatically be populated and handed off to the driver's specified probe
0168  * routine.
0169  */
0170 int superhyway_register_driver(struct superhyway_driver *drv)
0171 {
0172     drv->drv.name   = drv->name;
0173     drv->drv.bus    = &superhyway_bus_type;
0174 
0175     return driver_register(&drv->drv);
0176 }
0177 
0178 /**
0179  * superhyway_unregister_driver - Unregister a SuperHyway driver
0180  * @drv: SuperHyway driver to unregister.
0181  *
0182  * This cleans up after superhyway_register_driver(), and should be invoked in
0183  * the exit path of any module drivers.
0184  */
0185 void superhyway_unregister_driver(struct superhyway_driver *drv)
0186 {
0187     driver_unregister(&drv->drv);
0188 }
0189 
0190 static int superhyway_bus_match(struct device *dev, struct device_driver *drv)
0191 {
0192     struct superhyway_device *shyway_dev = to_superhyway_device(dev);
0193     struct superhyway_driver *shyway_drv = to_superhyway_driver(drv);
0194     const struct superhyway_device_id *ids = shyway_drv->id_table;
0195 
0196     if (!ids)
0197         return -EINVAL;
0198     if (superhyway_match_id(ids, shyway_dev))
0199         return 1;
0200 
0201     return -ENODEV;
0202 }
0203 
0204 struct bus_type superhyway_bus_type = {
0205     .name       = "superhyway",
0206     .match      = superhyway_bus_match,
0207 #ifdef CONFIG_SYSFS
0208     .dev_groups = superhyway_dev_groups,
0209 #endif
0210     .probe      = superhyway_device_probe,
0211     .remove     = superhyway_device_remove,
0212 };
0213 
0214 static int __init superhyway_bus_init(void)
0215 {
0216     return bus_register(&superhyway_bus_type);
0217 }
0218 
0219 static void __exit superhyway_bus_exit(void)
0220 {
0221     device_unregister(&superhyway_bus_device);
0222     bus_unregister(&superhyway_bus_type);
0223 }
0224 
0225 core_initcall(superhyway_bus_init);
0226 module_exit(superhyway_bus_exit);
0227 
0228 EXPORT_SYMBOL(superhyway_bus_type);
0229 EXPORT_SYMBOL(superhyway_add_device);
0230 EXPORT_SYMBOL(superhyway_add_devices);
0231 EXPORT_SYMBOL(superhyway_register_driver);
0232 EXPORT_SYMBOL(superhyway_unregister_driver);
0233 
0234 MODULE_LICENSE("GPL");