diff options
author | Srikant Patnaik | 2015-01-11 19:32:00 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 19:32:00 +0530 |
commit | b9ae4882794bcdc8d26671dfdbc406173d76c739 (patch) | |
tree | c38ab3721cf114958a1ba383ffa2a787cabe650f /drivers/media/video/wmt/wmt-vd.c | |
parent | 9269889243fe99dcec8609a7225cf3b55f879069 (diff) | |
download | FOSSEE-netbook-kernel-source-b9ae4882794bcdc8d26671dfdbc406173d76c739.tar.gz FOSSEE-netbook-kernel-source-b9ae4882794bcdc8d26671dfdbc406173d76c739.tar.bz2 FOSSEE-netbook-kernel-source-b9ae4882794bcdc8d26671dfdbc406173d76c739.zip |
source and header files added from another kernel source (not available in present repository)
Diffstat (limited to 'drivers/media/video/wmt/wmt-vd.c')
-rw-r--r-- | drivers/media/video/wmt/wmt-vd.c | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/drivers/media/video/wmt/wmt-vd.c b/drivers/media/video/wmt/wmt-vd.c new file mode 100644 index 00000000..435c375c --- /dev/null +++ b/drivers/media/video/wmt/wmt-vd.c @@ -0,0 +1,541 @@ +/*++ + * Common interface for WonderMedia SoC hardware decoder drivers + * + * Copyright (c) 2008-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 <http://www.gnu.org/licenses/>. + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ + +#include "wmt-vd.h" + +#define THE_MB_USER "WMT-VD" + +#define DRIVER_NAME "wmt-vd" + +#define VD_DEV_NAME "wmt-vd" + +/*#define VD_DEBUG_DEF*/ +/*#define VD_WORDY_DEF*/ + + +#define VD_INFO(fmt, args...) \ + do {\ + printk(KERN_INFO "[wmt-vd] " fmt , ## args);\ + } while (0) + +#define VD_WARN(fmt, args...) \ + do {\ + printk(KERN_WARNING "[wmt-vd] " fmt , ## args);\ + } while (0) + +#define VD_ERROR(fmt, args...) \ + do {\ + printk(KERN_ERR "[wmt-vd] " fmt , ## args);\ + } while (0) + +#ifdef VD_DEBUG_DEF +#define VD_DBG(fmt, args...) \ + do {\ + printk(KERN_DEBUG "[wmt-vd] %s: " fmt, __func__ , ## args);\ + } while (0) +#else +#define VD_DBG(fmt, args...) +#undef VD_WORDY_DEF +#endif + +#ifdef VD_WORDY_DEF +#define VD_WDBG(fmt, args...) VD_DBG(fmt, args...) +#else +#define VD_WDBG(fmt, args...) +#endif + + +static struct class *vd_class; +static int videodecoder_minor; +static int videodecoder_dev_nr = 1; +static struct cdev *videodecoder_cdev; + +static struct videodecoder *decoders[VD_MAX] = {0}; + +static struct vd_resource vd_res = { + .prdt = { NULL, 0x0, MAX_INPUT_BUF_SIZE}, +}; + +static DEFINE_SEMAPHORE(vd_sem); + +static int wmt_vd_open(struct inode *inode, struct file *filp) +{ + int ret = -EINVAL; + unsigned int idx = VD_MAX; + + down(&vd_sem); + idx = iminor(inode); + + if (idx < VD_MAX && decoders[idx]) { + struct videodecoder *vd = decoders[idx]; + + if (vd && vd->fops.open) { + if (idx == VD_JPEG) + filp->private_data = (void *)&(vd_res.prdt); + ret = vd->fops.open(inode, filp); + } + VD_DBG("decoder %s opened.\n", vd->name); + } + up(&vd_sem); + + return ret; +} /* End of wmt_vd_open() */ + +static int wmt_vd_release(struct inode *inode, struct file *filp) +{ + int ret = -EINVAL; + unsigned int idx = VD_MAX; + + down(&vd_sem); + idx = iminor(inode); + + if (idx < VD_MAX && decoders[idx]) { + struct videodecoder *vd = decoders[idx]; + if (vd && vd->fops.release) + ret = vd->fops.release(inode, filp); + VD_DBG("decoder %s closed.\n", vd->name); + } + up(&vd_sem); + + return ret; +} /* End of wmt_vd_release() */ + +static long wmt_vd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = -EINVAL; + unsigned int idx = VD_MAX; + struct inode *inode = filp->f_mapping->host; + + /* check type and number, if fail return ENOTTY */ + if ((_IOC_TYPE(cmd) != VD_IOC_MAGIC) || (_IOC_NR(cmd) > VD_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)); + + if (ret) + return -EFAULT; + + down(&vd_sem); + idx = iminor(inode); + if (idx < VD_MAX && decoders[idx]) { + struct videodecoder *vd = decoders[idx]; + + if (vd && vd->fops.unlocked_ioctl) + ret = vd->fops.unlocked_ioctl(filp, cmd, arg); + } + up(&vd_sem); + + return ret; +} /* End of wmt_vd_ioctl() */ + +static int wmt_vd_mmap(struct file *filp, struct vm_area_struct *vma) +{ + int ret = -EINVAL; + unsigned int idx = VD_MAX; + + down(&vd_sem); + if (filp && filp->f_dentry && filp->f_dentry->d_inode) + idx = iminor(filp->f_dentry->d_inode); + + if (idx < VD_MAX && decoders[idx]) { + struct videodecoder *vd = decoders[idx]; + if (vd && vd->fops.mmap) + ret = vd->fops.mmap(filp, vma); + } + up(&vd_sem); + + return ret; +} + +const struct file_operations videodecoder_fops = { + .owner = THIS_MODULE, + .open = wmt_vd_open, + .release = wmt_vd_release, + .unlocked_ioctl = wmt_vd_ioctl, + .mmap = wmt_vd_mmap, +}; + +static int wmt_vd_probe(struct platform_device *dev) +{ + dev_t dev_no; + int ret; + + dev_no = MKDEV(VD_MAJOR, videodecoder_minor); + + /* register char device */ + videodecoder_cdev = cdev_alloc(); + if (!videodecoder_cdev) { + VD_ERROR("alloc dev error.\n"); + return -ENOMEM; + } + + cdev_init(videodecoder_cdev, &videodecoder_fops); + ret = cdev_add(videodecoder_cdev, dev_no, 1); + + if (ret) { + VD_ERROR("reg char dev error(%d).\n", ret); + cdev_del(videodecoder_cdev); + return ret; + } + + vd_res.prdt.virt = dma_alloc_coherent(NULL, vd_res.prdt.size, + &vd_res.prdt.phys, GFP_KERNEL | GFP_DMA); + if (!vd_res.prdt.virt) { + VD_ERROR("allocate video PRDT buffer error.\n"); + cdev_del(videodecoder_cdev); + vd_res.prdt.virt = NULL; + vd_res.prdt.phys = 0; + return -ENOMEM; + } + + VD_DBG("prob /dev/%s major %d, minor %d, Resource:\n", + DRIVER_NAME, VD_MAJOR, videodecoder_minor); + + VD_DBG("PRDT %p/%x, size %d KB\n", + vd_res.prdt.virt, vd_res.prdt.phys, vd_res.prdt.size/1024); + + return ret; +} + +static int wmt_vd_remove(struct platform_device *dev) +{ + unsigned int idx = 0; + + down(&vd_sem); + while (idx < VD_MAX) { + if (decoders[idx] && decoders[idx]->remove) { + decoders[idx]->remove(); + decoders[idx] = NULL; + } + idx++; + } + up(&vd_sem); + + if (vd_res.prdt.virt) + dma_free_coherent(NULL, MAX_INPUT_BUF_SIZE, + vd_res.prdt.virt, vd_res.prdt.phys); + + return 0; +} + +static int wmt_vd_suspend(struct platform_device *dev, pm_message_t state) +{ + int ret; + unsigned int idx = 0; + + down(&vd_sem); + while (idx < VD_MAX) { + if (decoders[idx] && decoders[idx]->suspend) { + ret = decoders[idx]->suspend(state); + if (ret < 0) + VD_WARN("vdec %s suspend fail. ret:%d\n", + decoders[idx]->name, ret); + } + idx++; + } + up(&vd_sem); + + return 0; +} + +static int wmt_vd_resume(struct platform_device *dev) +{ + int ret; + unsigned int idx = 0; + + down(&vd_sem); + while (idx < VD_MAX) { + if (decoders[idx] && decoders[idx]->resume) { + ret = decoders[idx]->resume(); + if (ret < 0) { + VD_WARN("vdec %s resume fail. ret:%d\n", + decoders[idx]->name, ret); + } + } + idx++; + } + up(&vd_sem); + + return 0; +} + +static void wmt_vd_elease(struct device *device) +{ + unsigned int idx = 0; + + down(&vd_sem); + while (idx < VD_MAX) { + if (decoders[idx] && decoders[idx]->remove) { + decoders[idx]->remove(); + decoders[idx] = NULL; + } + idx++; + } + up(&vd_sem); + + if (vd_res.prdt.virt) + dma_free_coherent(NULL, MAX_INPUT_BUF_SIZE, + vd_res.prdt.virt, vd_res.prdt.phys); + + return; +} + +static struct platform_driver videodecoder_driver = { + .driver = { + .name = "wmt-vd", + .bus = &platform_bus_type, + }, + .probe = wmt_vd_probe, + .remove = wmt_vd_remove, + .suspend = wmt_vd_suspend, + .resume = wmt_vd_resume +}; + +static struct platform_device videodecoder_device = { + .name = "wmt-vd", + .id = 0, + .dev = { + .release = wmt_vd_elease, + }, + .num_resources = 0, /* ARRAY_SIZE(spi_resources), */ + .resource = NULL, /* spi_resources, */ +}; + +#ifdef CONFIG_PROC_FS +static int wmt_vd_read_proc( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + int size; + unsigned int idx = 0; + char *p; + + down(&vd_sem); + p = page; + p += sprintf(p, "***** video decoder information *****\n"); + + while (idx < VD_MAX) { + if (decoders[idx] && decoders[idx]->get_info) { + size = decoders[idx]->get_info(p, start, off, count); + count -= size; + if (count <= 40) + break; + p += size; + } + idx++; + } + p += sprintf(p, "**************** end ****************\n"); + up(&vd_sem); + + *eof = 1; + + return p - page; +} +#endif + +int wmt_vd_register(struct videodecoder *dec) +{ + int ret = 0; + dev_t dev_no; + + if (!dec || dec->id >= VD_MAX) { + VD_WARN("register invalid video decoder\n"); + return -1; + } + + if (decoders[dec->id]) { + VD_WARN("video decoder (ID=%d) exist.(E:%32s, N:%32s)\n", + dec->id, decoders[dec->id]->name, dec->name); + return -1; + } + + dev_no = MKDEV(VD_MAJOR, dec->id); + ret = register_chrdev_region(dev_no, videodecoder_dev_nr, dec->name); + if (ret < 0) { + VD_ERROR("can't get %s device minor %d\n", dec->name, dec->id); + return ret; + } + + dec->device = cdev_alloc(); + if (!dec->device) { + unregister_chrdev_region(dev_no, videodecoder_dev_nr); + VD_ERROR("alloc dev error\n"); + return -ENOMEM; + } + + cdev_init(dec->device, &videodecoder_fops); + ret = cdev_add(dec->device, dev_no, 1); + if (ret) { + VD_ERROR("reg char dev error(%d)\n", ret); + unregister_chrdev_region(dev_no, videodecoder_dev_nr); + cdev_del(dec->device); + dec->device = NULL; + return ret; + } + + if (dec->irq_num && dec->isr) { + ret = request_irq(dec->irq_num, dec->isr, + IRQF_SHARED, dec->name, dec->isr_data); + VD_INFO("%s Request IRQ %d %s.\n", + dec->name, dec->irq_num, (ret < 0) ? "Fail " : "Ok"); + if (ret) { + VD_ERROR("isr: 0x%p, isr_data: 0x%p (ret: %d)\n", + dec->isr, dec->isr_data, ret); + goto EXIT_wmt_vd_register; + } + } + + if (!ret) { + if (dec->setup) + ret = dec->setup(); + } + + if (ret >= 0) { + down(&vd_sem); + decoders[dec->id] = dec; + up(&vd_sem); + VD_INFO("%s registered major %d minor %d\n", + dec->name, VD_MAJOR, dec->id); + + /* let udev to handle /dev/ node */ + dec->vd_class = class_create(dec->fops.owner, dec->name); + device_create(dec->vd_class, 0, dev_no, 0, "%s", dec->name); + } else { + VD_ERROR("%s register major %d minor %d fail\n", + dec->name, VD_MAJOR, dec->id); + free_irq(dec->irq_num, (void *)dec->isr_data); + unregister_chrdev_region(dev_no, videodecoder_dev_nr); + cdev_del(dec->device); + dec->device = NULL; + } +EXIT_wmt_vd_register: + return ret; +} +EXPORT_SYMBOL(wmt_vd_register); + +int wmt_vd_unregister(struct videodecoder *dec) +{ + int ret = 0; + dev_t dev_no; + + if (!dec || dec->id >= VD_MAX || !dec->device) { + VD_WARN("unregister invalid video decoder\n"); + return -1; + } + + if (decoders[dec->id] != dec) { + VD_WARN("unregiseter wrong video decoder. (E:%32s, R:%32s)\n", + decoders[dec->id]->name, dec->name); + return -1; + } + + down(&vd_sem); + decoders[dec->id] = NULL; + up(&vd_sem); + + if (dec->remove) + ret = dec->remove(); + + dev_no = MKDEV(VD_MAJOR, dec->id); + free_irq(dec->irq_num, (void *)dec->isr_data); + + /* let udev to handle /dev/ node */ + device_destroy(dec->vd_class, dev_no); + class_destroy(dec->vd_class); + + unregister_chrdev_region(dev_no, videodecoder_dev_nr); + cdev_del(dec->device); + dec->device = NULL; + + return ret; +} +EXPORT_SYMBOL(wmt_vd_unregister); + +static int __init videodecoder_init(void) +{ + int ret; + dev_t dev_no; + + dev_no = MKDEV(VD_MAJOR, videodecoder_minor); + ret = register_chrdev_region(dev_no, videodecoder_dev_nr, "wmt-vd"); + if (ret < 0) { + VD_ERROR("can't get %s major %d\n", DRIVER_NAME, VD_MAJOR); + return ret; + } + +#ifdef CONFIG_PROC_FS + create_proc_read_entry("wmt-vd", 0, NULL, wmt_vd_read_proc, NULL); + VD_DBG("create video decoder proc\n"); +#endif + + ret = platform_driver_register(&videodecoder_driver); + if (!ret) { + ret = platform_device_register(&videodecoder_device); + if (ret) + platform_driver_unregister(&videodecoder_driver); + } + + /* let udev to handle /dev/wmt-vd */ + vd_class = class_create(THIS_MODULE, VD_DEV_NAME); + device_create(vd_class, NULL, dev_no, NULL, "%s", VD_DEV_NAME); + + VD_INFO("WonderMedia HW decoder driver inited\n"); + + return ret; +} + +void __exit videodecoder_exit(void) +{ + dev_t dev_no; + + platform_driver_unregister(&videodecoder_driver); + platform_device_unregister(&videodecoder_device); + dev_no = MKDEV(VD_MAJOR, videodecoder_minor); + + /* let udev to handle /dev/wmt-vd */ + device_destroy(vd_class, dev_no); + class_destroy(vd_class); + + unregister_chrdev_region(dev_no, videodecoder_dev_nr); + + VD_INFO("WonderMedia HW decoder driver exit\n"); + + return; +} + +fs_initcall(videodecoder_init); +module_exit(videodecoder_exit); + +MODULE_AUTHOR("WonderMedia Technologies, Inc."); +MODULE_DESCRIPTION("Video Codec device driver"); +MODULE_LICENSE("GPL"); + |