summaryrefslogtreecommitdiff
path: root/arch/arm/mach-sa1100/ipaq-sleeve-bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-sa1100/ipaq-sleeve-bus.c')
-rw-r--r--arch/arm/mach-sa1100/ipaq-sleeve-bus.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/arch/arm/mach-sa1100/ipaq-sleeve-bus.c b/arch/arm/mach-sa1100/ipaq-sleeve-bus.c
new file mode 100644
index 000000000000..9bf3201002b6
--- /dev/null
+++ b/arch/arm/mach-sa1100/ipaq-sleeve-bus.c
@@ -0,0 +1,124 @@
+#include <linux/ipaq-sleeve.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#define to_ipaq_option_driver(x) \
+ container_of(x, struct ipaq_option_driver, driver)
+
+static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct ipaq_option_device *idev = to_ipaq_option_device(dev);
+ return snprintf(buf, PAGE_SIZE, "%04x\n", idev->id.vendor);
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t device_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct ipaq_option_device *idev = to_ipaq_option_device(dev);
+ return snprintf(buf, PAGE_SIZE, "%04x\n", idev->id.device);
+}
+static DEVICE_ATTR_RO(device);
+
+static struct attribute *ipaq_option_sleeve_attrs[] = {
+ &dev_attr_vendor.attr,
+ &dev_attr_device.attr,
+ NULL,
+};
+
+static const struct attribute_group ipaq_option_sleeve_dev_group = {
+ .attrs = ipaq_option_sleeve_attrs,
+};
+
+static const struct attribute_group *ipaq_option_sleeve_dev_groups[] = {
+ &ipaq_option_sleeve_dev_group,
+ NULL,
+};
+
+static int ipaq_option_sleeve_match(struct device *dev, struct device_driver *drv)
+{
+ struct ipaq_option_device *idev = to_ipaq_option_device(dev);
+ struct ipaq_option_driver *idrv = to_ipaq_option_driver(drv);
+ const struct ipaq_option_id *id;
+
+ for (id = idrv->id_table; id->vendor || id->device; id++)
+ if (id->vendor == idev->id.vendor &&
+ id->device == idev->id.device)
+ return 1;
+
+ return 0;
+}
+
+static int ipaq_option_sleeve_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct ipaq_option_device *idev = to_ipaq_option_device(dev);
+
+ if (!dev)
+ return -ENODEV;
+
+ if (add_uevent_var(env, "MODALIAS=ipaq:v%04Xd%04X",
+ idev->id.vendor, idev->id.device))
+ return -ENOMEM;
+
+ return 0;
+}
+
+struct bus_type ipaq_option_sleeve_bus = {
+ .name = "ipaq-sleeve",
+ .dev_groups = ipaq_option_sleeve_dev_groups,
+ .match = ipaq_option_sleeve_match,
+ .uevent = ipaq_option_sleeve_uevent,
+};
+EXPORT_SYMBOL_GPL(ipaq_option_sleeve_bus);
+
+static void ipaq_option_release(struct device *dev)
+{
+ struct ipaq_option_device *opt_dev = to_ipaq_option_device(dev);
+
+ kfree(opt_dev);
+}
+
+int ipaq_option_device_add(struct device *parent, struct ipaq_option_id id)
+{
+ struct ipaq_option_device *idev;
+
+ idev = kzalloc(sizeof(*idev), GFP_KERNEL);
+ if (!idev)
+ return -ENOMEM;
+
+ idev->id = id;
+ device_initialize(&idev->dev);
+ dev_set_name(&idev->dev, "sleeve");
+ idev->dev.parent = parent;
+ idev->dev.release = ipaq_option_release;
+ idev->dev.bus = &ipaq_option_sleeve_bus;
+
+ return device_add(&idev->dev);
+}
+EXPORT_SYMBOL_GPL(ipaq_option_device_add);
+
+static int ipaq_option_device_remove(struct device *dev, void *data)
+{
+ device_unregister(dev);
+ return 0;
+}
+
+void ipaq_option_device_del(void)
+{
+ bus_for_each_dev(&ipaq_option_sleeve_bus, NULL, NULL,
+ ipaq_option_device_remove);
+}
+EXPORT_SYMBOL_GPL(ipaq_option_device_del);
+
+static int ipaq_option_sleeve_init(void)
+{
+ return bus_register(&ipaq_option_sleeve_bus);
+}
+core_initcall(ipaq_option_sleeve_init);
+
+static void ipaq_option_sleeve_exit(void)
+{
+ bus_unregister(&ipaq_option_sleeve_bus);
+}
+module_exit(ipaq_option_sleeve_exit);
+
+MODULE_LICENSE("GPL");