/* * Copyright (c) XMEDIA. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "base.h" /*****************************************************************************/ /**** media bus ****/ /*****************************************************************************/ static void media_bus_release(struct device *dev) { return; } struct device media_bus = { // change media_bus name from "media" to "gmp", because bus "media" is used in kenrel .init_name = "gmp", .release = media_bus_release }; #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) /* sysfs modalias store/show */ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { struct media_device *pdev = to_media_device(dev); int len = snprintf(buf, PAGE_SIZE, "media:%s\n", pdev->devfs_name); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } static struct device_attribute media_dev_attrs[] = { __ATTR_RO(modalias), __ATTR_NULL, }; #endif /* bus match & uevent */ static int media_match(struct device *dev, struct device_driver *drv) { struct media_device *pdev = to_media_device(dev); return (strncmp(pdev->devfs_name, drv->name, sizeof(pdev->devfs_name)) == 0); } static int media_uevent(struct device *dev, struct kobj_uevent_env *env) { struct media_device *pdev = to_media_device(dev); add_uevent_var(env, "MODALIAS=media:%s", pdev->devfs_name); return 0; } /*****************************************************************************/ // pm methods static int media_pm_prepare(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_prepare == NULL)) { return 0; } return pdrv->ops->pm_prepare(pdev); } static void media_pm_complete(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_complete == NULL)) { return; } pdrv->ops->pm_complete(pdev); } static int media_pm_suspend(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_suspend == NULL)) { return 0; } return pdrv->ops->pm_suspend(pdev); } static int media_pm_resume(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_resume == NULL)) { return 0; } return pdrv->ops->pm_resume(pdev); } static int media_pm_freeze(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_freeze == NULL)) { return 0; } return pdrv->ops->pm_freeze(pdev); } static int media_pm_thaw(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_thaw == NULL)) { return 0; } return pdrv->ops->pm_thaw(pdev); } static int media_pm_poweroff(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_poweroff == NULL)) { return 0; } return pdrv->ops->pm_poweroff(pdev); } static int media_pm_restore(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_restore == NULL)) { return 0; } return pdrv->ops->pm_restore(pdev); } static int media_pm_suspend_noirq(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_suspend_noirq == NULL)) { return 0; } return pdrv->ops->pm_suspend_noirq(pdev); } static int media_pm_resume_noirq(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_resume_noirq == NULL)) { return 0; } return pdrv->ops->pm_resume_noirq(pdev); } static int media_pm_freeze_noirq(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_freeze_noirq == NULL)) { return 0; } return pdrv->ops->pm_freeze_noirq(pdev); } static int media_pm_thaw_noirq(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_thaw_noirq == NULL)) { return 0; } return pdrv->ops->pm_thaw_noirq(pdev); } static int media_pm_poweroff_noirq(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_poweroff_noirq == NULL)) { return 0; } return pdrv->ops->pm_poweroff_noirq(pdev); } static int media_pm_restore_noirq(struct device *dev) { struct media_device *pdev = to_media_device(dev); struct media_driver *pdrv = to_media_driver(dev->driver); if ((pdrv->ops == NULL) || (pdrv->ops->pm_restore_noirq == NULL)) { return 0; } return pdrv->ops->pm_restore_noirq(pdev); } static struct dev_pm_ops media_bus_pm_ops = { .prepare = media_pm_prepare, .complete = media_pm_complete, // with irq .suspend = media_pm_suspend, .resume = media_pm_resume, .freeze = media_pm_freeze, .thaw = media_pm_thaw, .poweroff = media_pm_poweroff, .restore = media_pm_restore, // with noirq .suspend_noirq = media_pm_suspend_noirq, .resume_noirq = media_pm_resume_noirq, .freeze_noirq = media_pm_freeze_noirq, .thaw_noirq = media_pm_thaw_noirq, .poweroff_noirq = media_pm_poweroff_noirq, .restore_noirq = media_pm_restore_noirq, }; struct bus_type media_bus_type = { // change media_bus name from "media" to "gmp", because bus "media" is used in kenrel .name = "gmp", #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) .dev_attrs = media_dev_attrs, #endif .match = media_match, .uevent = media_uevent, .pm = &media_bus_pm_ops, }; int media_bus_init(void) { int ret; ret = device_register(&media_bus); if (ret) { return ret; } ret = bus_register(&media_bus_type); if (ret) { goto error; } return 0; error: device_unregister(&media_bus); return ret; } void media_bus_exit(void) { bus_unregister(&media_bus_type); device_unregister(&media_bus); } static void media_device_release(struct device *dev) { return; } int _media_device_register(struct media_device *pdev) { dev_set_name(&pdev->device, "%s", pdev->devfs_name); pdev->device.devt = MKDEV(MEDIA_DEVICE_MAJOR, pdev->minor); pdev->device.release = media_device_release; pdev->device.bus = &media_bus_type; return device_register(&pdev->device); } void _media_device_unregister(struct media_device *pdev) { device_unregister(&pdev->device); } struct media_driver *media_driver_register(const char *name, struct module *owner, struct media_ops *ops) { int ret; struct media_driver *pdrv = NULL; #ifdef MODULE if ((name == NULL) || (owner == NULL)) { #else if (name == NULL){ #endif return ERR_PTR(-EINVAL); } pdrv = kzalloc(sizeof(struct media_driver) + strnlen(name, MEDIA_MAX_DEV_NAME_LEN), GFP_KERNEL); if (pdrv == NULL) { return ERR_PTR(-ENOMEM); } /* init driver object */ strncpy(pdrv->name, name, strnlen(name, MEDIA_MAX_DEV_NAME_LEN)); pdrv->ops = ops; pdrv->driver.name = pdrv->name; pdrv->driver.owner = owner; pdrv->driver.bus = &media_bus_type; ret = driver_register(&pdrv->driver); if (ret) { kfree(pdrv); return ERR_PTR(ret); } return pdrv; } void media_driver_unregister(struct media_driver *pdrv) { if (pdrv != NULL) { driver_unregister(&pdrv->driver); kfree(pdrv); } } // end! /*****************************************************************************/