/* * arch/sh/kernel/cpu/bus.c * * Virtual bus for SuperH. * * Copyright (C) 2004 Paul Mundt * * Shamelessly cloned from arch/arm/mach-omap/bus.c, which was written * by: * * Copyright (C) 2003 - 2004 Nokia Corporation * Written by Tony Lindgren * Portions of code based on sa1111.c. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ #include #include #include #include #include static int sh_bus_match(struct device *dev, struct device_driver *drv) { struct sh_driver *shdrv = to_sh_driver(drv); struct sh_dev *shdev = to_sh_dev(dev); return shdev->dev_id == shdrv->dev_id; } static int sh_bus_suspend(struct device *dev, pm_message_t state) { struct sh_dev *shdev = to_sh_dev(dev); struct sh_driver *shdrv = to_sh_driver(dev->driver); if (shdrv && shdrv->suspend) return shdrv->suspend(shdev, state); return 0; } static int sh_bus_resume(struct device *dev) { struct sh_dev *shdev = to_sh_dev(dev); struct sh_driver *shdrv = to_sh_driver(dev->driver); if (shdrv && shdrv->resume) return shdrv->resume(shdev); return 0; } static int sh_device_probe(struct device *dev) { struct sh_dev *shdev = to_sh_dev(dev); struct sh_driver *shdrv = to_sh_driver(dev->driver); if (shdrv && shdrv->probe) return shdrv->probe(shdev); return -ENODEV; } static int sh_device_remove(struct device *dev) { struct sh_dev *shdev = to_sh_dev(dev); struct sh_driver *shdrv = to_sh_driver(dev->driver); if (shdrv && shdrv->remove) return shdrv->remove(shdev); return 0; } static struct device sh_bus_devices[SH_NR_BUSES] = { { .bus_id = SH_BUS_NAME_VIRT, }, }; struct bus_type sh_bus_types[SH_NR_BUSES] = { { .name = SH_BUS_NAME_VIRT, .match = sh_bus_match, .probe = sh_bus_probe, .remove = sh_bus_remove, .suspend = sh_bus_suspend, .resume = sh_bus_resume, }, }; int sh_device_register(struct sh_dev *dev) { if (!dev) return -EINVAL; if (dev->bus_id < 0 || dev->bus_id >= SH_NR_BUSES) { printk(KERN_ERR "%s: bus_id invalid: %s bus: %d\n", __FUNCTION__, dev->name, dev->bus_id); return -EINVAL; } dev->dev.parent = &sh_bus_devices[dev->bus_id]; dev->dev.bus = &sh_bus_types[dev->bus_id]; /* This is needed for USB OHCI to work */ if (dev->dma_mask) dev->dev.dma_mask = dev->dma_mask; snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%s%u", dev->name, dev->dev_id); printk(KERN_INFO "Registering SH device '%s'. Parent at %s\n", dev->dev.bus_id, dev->dev.parent->bus_id); return device_register(&dev->dev); } void sh_device_unregister(struct sh_dev *dev) { device_unregister(&dev->dev); } int sh_driver_register(struct sh_driver *drv) { if (!drv) return -EINVAL; if (drv->bus_id < 0 || drv->bus_id >= SH_NR_BUSES) { printk(KERN_ERR "%s: bus_id invalid: bus: %d device %d\n", __FUNCTION__, drv->bus_id, drv->dev_id); return -EINVAL; } drv->drv.bus = &sh_bus_types[drv->bus_id]; return driver_register(&drv->drv); } void sh_driver_unregister(struct sh_driver *drv) { driver_unregister(&drv->drv); } static int __init sh_bus_init(void) { int i, ret = 0; for (i = 0; i < SH_NR_BUSES; i++) { ret = device_register(&sh_bus_devices[i]); if (ret != 0) { printk(KERN_ERR "Unable to register bus device %s\n", sh_bus_devices[i].bus_id); continue; } ret = bus_register(&sh_bus_types[i]); if (ret != 0) { printk(KERN_ERR "Unable to register bus %s\n", sh_bus_types[i].name); device_unregister(&sh_bus_devices[i]); } } printk(KERN_INFO "SH Virtual Bus initialized\n"); return ret; } static void __exit sh_bus_exit(void) { int i; for (i = 0; i < SH_NR_BUSES; i++) { bus_unregister(&sh_bus_types[i]); device_unregister(&sh_bus_devices[i]); } } module_init(sh_bus_init); module_exit(sh_bus_exit); MODULE_AUTHOR("Paul Mundt "); MODULE_DESCRIPTION("SH Virtual Bus"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(sh_bus_types); EXPORT_SYMBOL(sh_device_register); EXPORT_SYMBOL(sh_device_unregister); EXPORT_SYMBOL(sh_driver_register); EXPORT_SYMBOL(sh_driver_unregister);