/*++ * linux/drivers/video/wmt/wmt-sync.c * WonderMedia video post processor (VPP) driver * * Copyright c 2013 WonderMedia Technologies, Inc. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * WonderMedia Technologies, Inc. * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C --*/ #define DEV_SYNC_C #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef DEBUG /* #define DEBUG */ /* #define DEBUG_DETAIL */ #include "vpp.h" #define DEVICE_NAME "wmt-sync" static DEFINE_SEMAPHORE(wmt_sync_sem); static DECLARE_WAIT_QUEUE_HEAD(wmt_sync_wait); static struct class *wmt_sync_class; static int wmt_sync_major; unsigned int wmt_vsync_flag; int wmt_sync_set_vsync(void *arg) { wmt_vsync_flag++; wake_up_interruptible(&wmt_sync_wait); vpp_mb_irqproc_sync(0); return 0; } static int wmt_sync_open( struct inode *inode, struct file *filp ) { int ret = 0; vpp_int_t type; DBG_MSG("\n"); down(&wmt_sync_sem); if (g_vpp.dual_display) { type = (vout_info[0].govr_mod == VPP_MOD_GOVRH) ? VPP_INT_GOVRH_VBIS : VPP_INT_GOVRH2_VBIS; } else { type = VPP_INT_GOVRH2_VBIS; /* HDMI should slow down */ } vpp_irqproc_work(type, wmt_sync_set_vsync, 0, 0, 0); up(&wmt_sync_sem); return ret; } /* End of wmt_sync_open() */ static int wmt_sync_release( struct inode *inode, struct file *filp ) { int ret = 0; vpp_int_t type; DBG_MSG("\n"); down(&wmt_sync_sem); type = (vout_info[0].govr_mod == VPP_MOD_GOVRH) ? VPP_INT_GOVRH_VBIS : VPP_INT_GOVRH2_VBIS; vpp_irqproc_del_work(type, wmt_sync_set_vsync); up(&wmt_sync_sem); return ret; } /* End of wmt_sync_release() */ static long wmt_sync_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret = -EINVAL; DBG_MSG("0x%x,0x%x\n", cmd, arg); /* check type and number, if fail return ENOTTY */ if (_IOC_TYPE(cmd) != WMT_CEC_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > WMT_CEC_IOC_MAXNR) return -ENOTTY; /* check argument area */ if (_IOC_DIR(cmd) & _IOC_READ) ret = !access_ok(VERIFY_WRITE, (void __user *) arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) ret = !access_ok(VERIFY_READ, (void __user *) arg, _IOC_SIZE(cmd)); else ret = 0; if (ret) return -EFAULT; down(&wmt_sync_sem); switch (cmd) { default: DBG_ERR("*W* cmd 0x%x\n", cmd); break; } up(&wmt_sync_sem); return ret; } /* End of wmt_sync_ioctl() */ static ssize_t wmt_sync_read( struct file *filp, char __user *buf, size_t count, loff_t *f_pos ) { unsigned long data; ssize_t retval = 0; down(&wmt_sync_sem); if (filp->f_flags & O_NONBLOCK && !wmt_vsync_flag) { retval = -EAGAIN; goto read_end; } data = xchg(&wmt_vsync_flag, 0); retval = wait_event_interruptible(wmt_sync_wait, data); if (retval == 0) retval = put_user(data, (unsigned int __user *)buf); read_end: up(&wmt_sync_sem); return retval; } /* wmt_sync_read */ static ssize_t wmt_sync_write( struct file *filp, const char __user *buf, size_t count, loff_t *f_pos ) { ssize_t ret = 0; down(&wmt_sync_sem); /* TODO */ up(&wmt_sync_sem); return ret; } /* End of wmt_sync_write() */ static unsigned int wmt_sync_poll( struct file *filp, struct poll_table_struct *wait ) { unsigned int mask = 0; down(&wmt_sync_sem); poll_wait(filp, &wmt_sync_wait, wait); if (wmt_vsync_flag != 0) mask |= POLLIN | POLLRDNORM; up(&wmt_sync_sem); return mask; } const struct file_operations wmt_sync_fops = { .owner = THIS_MODULE, .open = wmt_sync_open, .release = wmt_sync_release, .read = wmt_sync_read, .write = wmt_sync_write, .unlocked_ioctl = wmt_sync_ioctl, .poll = wmt_sync_poll, }; static int wmt_sync_probe ( struct platform_device *dev /*!<; // a pointer to struct device */ ) { return 0; } /* End of wmt_sync_probe */ static int wmt_sync_remove ( struct platform_device *dev /*!<; // a pointer to struct device */ ) { return 0; } /* End of wmt_sync_remove */ #ifdef CONFIG_PM static int wmt_sync_suspend ( struct platform_device *pDev, /*!<; // a pointer to struct device */ pm_message_t state /*!<; // suspend state */ ) { DPRINT("Enter wmt_sync_suspend\n"); return 0; } /* End of wmt_sync_suspend */ static int wmt_sync_resume ( struct platform_device *pDev /*!<; // a pointer to struct device */ ) { DPRINT("Enter wmt_sync_resume\n"); return 0; } /* End of wmt_sync_resume */ #else #define wmt_sync_suspend NULL #define wmt_sync_resume NULL #endif /*************************************************************************** device driver struct define ****************************************************************************/ static struct platform_driver wmt_sync_driver = { .driver.name = DEVICE_NAME, /* equal to platform device name. */ /* .bus = &platform_bus_type, */ .probe = wmt_sync_probe, .remove = wmt_sync_remove, .suspend = wmt_sync_suspend, .resume = wmt_sync_resume, }; static void wmt_sync_platform_release(struct device *device) { } /* End of wmt_sync_platform_release() */ /*************************************************************************** platform device struct define ****************************************************************************/ /* static u64 wmt_sync_dma_mask = 0xffffffffUL; */ static struct platform_device wmt_sync_device = { .name = DEVICE_NAME, .id = 0, .dev = { .release = wmt_sync_platform_release, #if 0 .dma_mask = &wmt_sync_dma_mask, .coherent_dma_mask = ~0, #endif }, .num_resources = 0, /* ARRAY_SIZE(cipher_resources), */ .resource = NULL, /* cipher_resources, */ }; static int __init wmt_sync_init(void) { int ret; char buf[100]; int varlen = 100; unsigned int sync_enable = 1; /* default enable */ dev_t dev_no; if (wmt_getsyspara("wmt.display.sync", buf, &varlen) == 0) vpp_parse_param(buf, &sync_enable, 1, 0); if (sync_enable == 0) return 0; wmt_sync_major = register_chrdev(0, DEVICE_NAME, &wmt_sync_fops); if (wmt_sync_major < 0) { DBG_ERR("get gpio_dev_major failed\n"); return -EFAULT; } wmt_sync_class = class_create(THIS_MODULE, DEVICE_NAME); if (IS_ERR(wmt_sync_class)) { ret = PTR_ERR(wmt_sync_class); DBG_ERR("Can't create class : %s !!\n", DEVICE_NAME); return ret; } dev_no = MKDEV(wmt_sync_major, 0); device_create(wmt_sync_class, NULL, dev_no, NULL, DEVICE_NAME); ret = platform_device_register(&wmt_sync_device); if (ret != 0) return -ENODEV; ret = platform_driver_register(&wmt_sync_driver); if (ret != 0) { platform_device_unregister(&wmt_sync_device); return -ENODEV; } return 0; } static void __exit wmt_sync_exit(void) { dev_t dev_no; DBG_MSG("\n"); platform_driver_unregister(&wmt_sync_driver); platform_device_unregister(&wmt_sync_device); dev_no = MKDEV(wmt_sync_major, 0); device_destroy(wmt_sync_class, dev_no); class_destroy(wmt_sync_class); unregister_chrdev(wmt_sync_major, DEVICE_NAME); return; } module_init(wmt_sync_init); module_exit(wmt_sync_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("WMT SYNC driver"); MODULE_AUTHOR("WMT TECH"); MODULE_VERSION("1.0.0");