0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
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
0164
0165
0166
0167
0168
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
0180
0181
0182
0183
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");