diff options
Diffstat (limited to 'arch/arm/mach-sa1100/ipaq-sleeve-bus.c')
-rw-r--r-- | arch/arm/mach-sa1100/ipaq-sleeve-bus.c | 124 |
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"); |