953 lines
29 KiB
C
953 lines
29 KiB
C
/*
|
|
* Copyright (c) XMEDIA. All rights reserved.
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/printk.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/mm_types.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/kmod.h>
|
|
#include <linux/devfreq.h>
|
|
#include "media.h"
|
|
#include "osal.h"
|
|
#include "osal_devfreq.h"
|
|
|
|
#define DRVAL_DEBUG 0
|
|
|
|
#define GET_FILE(file) \
|
|
do { \
|
|
if (__get_file(file) < 0) \
|
|
return -1; \
|
|
} while (0)
|
|
|
|
#define PUT_FILE(file) \
|
|
do { \
|
|
if (__put_file(file) < 0) \
|
|
return -1; \
|
|
} while (0)
|
|
|
|
typedef struct osal_coat_dev {
|
|
struct osal_dev osal_dev;
|
|
struct media_device media_dev;
|
|
} osal_coat_dev_t;
|
|
|
|
struct osal_private_data {
|
|
struct osal_dev *dev;
|
|
void *data;
|
|
struct osal_poll table;
|
|
int f_ref_cnt;
|
|
};
|
|
|
|
spinlock_t f_lock;
|
|
|
|
void osal_device_init(void)
|
|
{
|
|
spin_lock_init(&f_lock);
|
|
}
|
|
|
|
static int __get_file(struct file *file)
|
|
{
|
|
struct osal_private_data *pdata = NULL;
|
|
|
|
spin_lock(&f_lock);
|
|
pdata = file->private_data;
|
|
if (pdata == NULL) {
|
|
spin_unlock(&f_lock);
|
|
return -1;
|
|
}
|
|
|
|
pdata->f_ref_cnt++;
|
|
spin_unlock(&f_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __put_file(struct file *file)
|
|
{
|
|
struct osal_private_data *pdata = NULL;
|
|
|
|
spin_lock(&f_lock);
|
|
pdata = file->private_data;
|
|
if (pdata == NULL) {
|
|
spin_unlock(&f_lock);
|
|
return -1;
|
|
}
|
|
|
|
pdata->f_ref_cnt--;
|
|
spin_unlock(&f_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int osal_open(struct inode *inode, struct file *file)
|
|
{
|
|
struct media_device *media = NULL;
|
|
osal_coat_dev_t *coat_dev = NULL;
|
|
struct osal_private_data *pdata = NULL;
|
|
|
|
if (!capable(CAP_SYS_RAWIO) || !capable(CAP_SYS_ADMIN)) {
|
|
return -EPERM;
|
|
}
|
|
|
|
// media = getmedia(inode);
|
|
media = (struct media_device *)file->private_data;
|
|
if (media == NULL) {
|
|
osal_printk("%s - get media device error!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
coat_dev = osal_container_of(media, struct osal_coat_dev, media_dev);
|
|
pdata = (struct osal_private_data *)kmalloc(sizeof(struct osal_private_data), GFP_KERNEL);
|
|
if (pdata == NULL) {
|
|
osal_printk("%s - kmalloc error!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - file->private_data=%pK!\n", __FUNCTION__, pdata);
|
|
}
|
|
|
|
memset(pdata, 0, sizeof(struct osal_private_data));
|
|
|
|
file->private_data = pdata;
|
|
pdata->dev = &(coat_dev->osal_dev);
|
|
if (coat_dev->osal_dev.fops->open != NULL) {
|
|
return coat_dev->osal_dev.fops->open((void *)&(pdata->data));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t osal_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
|
|
{
|
|
struct osal_private_data *pdata = file->private_data;
|
|
int ret = 0;
|
|
|
|
GET_FILE(file);
|
|
|
|
if (pdata->dev->fops->read != NULL) {
|
|
ret = pdata->dev->fops->read(buf, (int)size, (long *)offset, (void *)&(pdata->data));
|
|
}
|
|
|
|
PUT_FILE(file);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t osal_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
|
|
{
|
|
struct osal_private_data *pdata = file->private_data;
|
|
int ret = 0;
|
|
|
|
GET_FILE(file);
|
|
if (pdata->dev->fops->write != NULL) {
|
|
ret = pdata->dev->fops->write(buf, (int)size, (long *)offset, (void *)&(pdata->data));
|
|
}
|
|
PUT_FILE(file);
|
|
return ret;
|
|
}
|
|
|
|
static loff_t osal_llseek(struct file *file, loff_t offset, int whence)
|
|
{
|
|
struct osal_private_data *pdata = file->private_data;
|
|
int ret = 0;
|
|
|
|
GET_FILE(file);
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - file->private_data=%pK!\n", __FUNCTION__, pdata);
|
|
}
|
|
|
|
if (whence == SEEK_SET) {
|
|
if (pdata->dev->fops->llseek != NULL) {
|
|
ret = pdata->dev->fops->llseek((long)offset, OSAL_SEEK_SET, (void *)&(pdata->data));
|
|
}
|
|
} else if (whence == SEEK_CUR) {
|
|
if (pdata->dev->fops->llseek != NULL) {
|
|
ret = pdata->dev->fops->llseek((long)offset, OSAL_SEEK_CUR, (void *)&(pdata->data));
|
|
}
|
|
} else if (whence == SEEK_END) {
|
|
if (pdata->dev->fops->llseek != NULL) {
|
|
ret = pdata->dev->fops->llseek((long)offset, OSAL_SEEK_END, (void *)&(pdata->data));
|
|
}
|
|
}
|
|
|
|
PUT_FILE(file);
|
|
return (loff_t)ret;
|
|
}
|
|
|
|
static int osal_release(struct inode *inode, struct file *file)
|
|
{
|
|
int ret = 0;
|
|
struct osal_private_data *pdata = file->private_data;
|
|
|
|
GET_FILE(file);
|
|
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - file->private_data=%pK!\n", __FUNCTION__, pdata);
|
|
}
|
|
|
|
if (pdata->dev->fops->release != NULL) {
|
|
ret = pdata->dev->fops->release((void *)&(pdata->data));
|
|
}
|
|
if (ret != 0) {
|
|
PUT_FILE(file);
|
|
osal_printk("%s - release failed!\n", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
|
|
PUT_FILE(file);
|
|
spin_lock(&f_lock);
|
|
if (pdata->f_ref_cnt != 0) {
|
|
osal_printk("%s - release failed!\n", __FUNCTION__);
|
|
spin_unlock(&f_lock);
|
|
return -1;
|
|
}
|
|
kfree(file->private_data);
|
|
file->private_data = NULL;
|
|
spin_unlock(&f_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static long __osal_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
int ret = -1;
|
|
struct osal_private_data *pdata = file->private_data;
|
|
char *kbuf = NULL;
|
|
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - file->private_data=%pK!\n", __FUNCTION__, pdata);
|
|
}
|
|
|
|
if (((_IOC_SIZE(cmd) == 0) && (_IOC_DIR(cmd) != _IOC_NONE))) {
|
|
return -1;
|
|
}
|
|
|
|
if ((_IOC_DIR(cmd) != _IOC_NONE) && (((char *)(uintptr_t)arg) == NULL)) {
|
|
osal_printk("%s - Input param err,it is null!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if (_IOC_DIR(cmd) == _IOC_NONE) {
|
|
if (pdata->dev->fops->unlocked_ioctl == NULL) {
|
|
return -1;
|
|
} else {
|
|
ret = pdata->dev->fops->unlocked_ioctl(cmd, arg, (void *)&(pdata->data));
|
|
}
|
|
} else if (_IOC_DIR(cmd) == _IOC_WRITE) {
|
|
kbuf = (char *)vmalloc(_IOC_SIZE(cmd));
|
|
if (kbuf == NULL) {
|
|
osal_printk("%s - vmalloc failed!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if (copy_from_user(kbuf, (char *)(uintptr_t)arg, _IOC_SIZE(cmd))) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
}
|
|
|
|
if (pdata->dev->fops->unlocked_ioctl == NULL) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
} else {
|
|
ret = pdata->dev->fops->unlocked_ioctl (cmd, (unsigned long)(uintptr_t)kbuf, (void *)&(pdata->data));
|
|
}
|
|
} else if (_IOC_DIR(cmd) == _IOC_READ) {
|
|
kbuf = vmalloc(_IOC_SIZE(cmd));
|
|
if (kbuf == NULL) {
|
|
osal_printk("%s - vmalloc failed!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
if (pdata->dev->fops->unlocked_ioctl == NULL) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
} else {
|
|
ret = pdata->dev->fops->unlocked_ioctl (cmd, (unsigned long)(uintptr_t)kbuf, (void *)&(pdata->data));
|
|
if (ret == 0) {
|
|
if (copy_to_user((char *)(uintptr_t)arg, kbuf, _IOC_SIZE(cmd))) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
} else if (_IOC_DIR(cmd) == (_IOC_READ + _IOC_WRITE)) {
|
|
kbuf = vmalloc(_IOC_SIZE(cmd));
|
|
if (kbuf == NULL) {
|
|
osal_printk("%s - vmalloc failed!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if (copy_from_user(kbuf, (char *)(uintptr_t)arg, _IOC_SIZE(cmd))) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
}
|
|
|
|
if (pdata->dev->fops->unlocked_ioctl == NULL) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
} else {
|
|
ret = pdata->dev->fops->unlocked_ioctl (cmd, (unsigned long)(uintptr_t)kbuf, (void *)&(pdata->data));
|
|
if (ret == 0) {
|
|
if (copy_to_user((char *)(uintptr_t)arg, kbuf, _IOC_SIZE(cmd))) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (kbuf != NULL) {
|
|
vfree(kbuf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static long osal_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
long ret = 0;
|
|
|
|
GET_FILE(file);
|
|
|
|
ret = __osal_unlocked_ioctl(file, cmd, arg);
|
|
PUT_FILE(file);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
static long __osal_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
int ret = -1;
|
|
struct osal_private_data *pdata = file->private_data;
|
|
char *kbuf = NULL;
|
|
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - file->private_data=%pK!\n", __FUNCTION__, pdata);
|
|
}
|
|
|
|
if (((_IOC_SIZE(cmd) == 0) && (_IOC_DIR(cmd) != _IOC_NONE))) {
|
|
return -1;
|
|
}
|
|
|
|
if ((_IOC_DIR(cmd) != _IOC_NONE) && (((char *)(uintptr_t)arg) == NULL)) {
|
|
osal_printk("%s - Input param err,it is null!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if (_IOC_DIR(cmd) == _IOC_NONE) {
|
|
if (pdata->dev->fops->compat_ioctl == NULL) {
|
|
return -1;
|
|
} else {
|
|
ret = pdata->dev->fops->compat_ioctl(cmd, arg, (void *)&(pdata->data));
|
|
}
|
|
} else if (_IOC_DIR(cmd) == _IOC_WRITE) {
|
|
kbuf = (char *)vmalloc(_IOC_SIZE(cmd));
|
|
if (kbuf == NULL) {
|
|
osal_printk("%s - vmalloc failed!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if (copy_from_user(kbuf, (char *)(uintptr_t)arg, _IOC_SIZE(cmd))) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
}
|
|
|
|
if (pdata->dev->fops->compat_ioctl == NULL) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
} else {
|
|
ret = pdata->dev->fops->compat_ioctl (cmd, (unsigned long)(uintptr_t)kbuf, (void *)&(pdata->data));
|
|
}
|
|
} else if (_IOC_DIR(cmd) == _IOC_READ) {
|
|
kbuf = vmalloc(_IOC_SIZE(cmd));
|
|
if (kbuf == NULL) {
|
|
osal_printk("%s - vmalloc failed!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
if (pdata->dev->fops->compat_ioctl == NULL) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
} else {
|
|
ret = pdata->dev->fops->compat_ioctl (cmd, (unsigned long)(uintptr_t)kbuf, (void *)&(pdata->data));
|
|
if (ret == 0) {
|
|
if (copy_to_user((char *)(uintptr_t)arg, kbuf, _IOC_SIZE(cmd))) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
} else if (_IOC_DIR(cmd) == (_IOC_READ + _IOC_WRITE)) {
|
|
kbuf = vmalloc(_IOC_SIZE(cmd));
|
|
if (kbuf == NULL) {
|
|
osal_printk("%s - vmalloc failed!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
if (copy_from_user(kbuf, (char *)(uintptr_t)arg, _IOC_SIZE(cmd))) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
}
|
|
|
|
if (pdata->dev->fops->compat_ioctl == NULL) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
} else {
|
|
ret = pdata->dev->fops->compat_ioctl (cmd, (unsigned long)(uintptr_t)kbuf, (void *)&(pdata->data));
|
|
if (ret == 0) {
|
|
if (copy_to_user((char *)(uintptr_t)arg, kbuf, _IOC_SIZE(cmd))) {
|
|
vfree(kbuf);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (kbuf != NULL) {
|
|
vfree(kbuf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static long osal_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
long ret = 0;
|
|
|
|
GET_FILE(file);
|
|
|
|
ret = __osal_compat_ioctl(file, cmd, arg);
|
|
PUT_FILE(file);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|
|
static unsigned int osal_poll(struct file *file, struct poll_table_struct *table)
|
|
{
|
|
struct osal_private_data *pdata = file->private_data;
|
|
struct osal_poll t;
|
|
unsigned int ret = 0;
|
|
|
|
GET_FILE(file);
|
|
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - table=%pK, file=%pK!\n", __FUNCTION__, table, file);
|
|
}
|
|
t.poll_table = table;
|
|
t.data = file;
|
|
if (pdata->dev->fops->poll != NULL) {
|
|
ret = pdata->dev->fops->poll(&t, (void *)&(pdata->data));
|
|
}
|
|
|
|
PUT_FILE(file);
|
|
return ret;
|
|
}
|
|
|
|
static int __osal_valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
|
|
{
|
|
/* check physical addr greater than the max addr supported by the system */
|
|
if ((pfn + (size >> PAGE_SHIFT)) > (1 + ((~0UL) >> PAGE_SHIFT))) {
|
|
osal_printk("--%s - %d--!\n", __FUNCTION__, __LINE__);
|
|
return 0;
|
|
}
|
|
|
|
/* CMA need to alloc ram region, so annotate the code as follows */
|
|
#if 0
|
|
/* check physical addr is ram region */
|
|
if (pfn_valid(pfn) || pfn_valid(pfn + (size >> PAGE_SHIFT))) {
|
|
osal_printk("--%s - %d--!\n", __FUNCTION__, __LINE__);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* It's necessary for the variable "size" to align 4k(page_size). */
|
|
#define PAGE_SIZE_MASK 0xfffffffffffff000ULL
|
|
if ((unsigned long)size & (~PAGE_SIZE_MASK)) {
|
|
osal_printk("--%s - %d--!\n", __FUNCTION__, __LINE__);
|
|
return 0;
|
|
}
|
|
#undef PAGE_SIZE_MASK
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int osal_mmap(struct file *file, struct vm_area_struct *vm)
|
|
{
|
|
struct osal_vm osal_vm;
|
|
struct osal_private_data *pdata = file->private_data;
|
|
osal_vm.vm = vm;
|
|
|
|
if (!__osal_valid_mmap_phys_addr_range(vm->vm_pgoff, vm->vm_end - vm->vm_start)) {
|
|
osal_printk("\n%s - invalid argument size=%ld!!!\n", __FUNCTION__, vm->vm_end - vm->vm_start);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - start=%lx, end=%lx!, off=%lx\n", __FUNCTION__, vm->vm_start, vm->vm_end, vm->vm_pgoff);
|
|
}
|
|
if (pdata->dev->fops->mmap != NULL) {
|
|
return pdata->dev->fops->mmap(&osal_vm, vm->vm_start, vm->vm_end, vm->vm_pgoff, (void *)&(pdata->data));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct file_operations s_osal_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = osal_open,
|
|
.read = osal_read,
|
|
.write = osal_write,
|
|
.llseek = osal_llseek,
|
|
.unlocked_ioctl = osal_unlocked_ioctl,
|
|
.release = osal_release,
|
|
.poll = osal_poll,
|
|
.mmap = osal_mmap,
|
|
#ifdef CONFIG_COMPAT
|
|
.compat_ioctl = osal_compat_ioctl,
|
|
#endif
|
|
};
|
|
|
|
static int osal_pm_prepare(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_prepare) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_prepare(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void osal_pm_complete(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_complete) {
|
|
coat_dev->osal_dev.osal_pmops->pm_complete(&(coat_dev->osal_dev));
|
|
}
|
|
}
|
|
|
|
static int osal_pm_suspend(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_suspend) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_suspend(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_resume(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_resume) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_resume(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_freeze(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_freeze) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_freeze(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_thaw(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_thaw) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_thaw(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_poweroff(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_poweroff) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_poweroff(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_restore(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_restore) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_restore(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_suspend_late(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_suspend_late) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_suspend_late(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_resume_early(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_resume_early) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_resume_early(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_freeze_late(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_freeze_late) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_freeze_late(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_thaw_early(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_thaw_early) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_thaw_early(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_poweroff_late(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_poweroff_late) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_poweroff_late(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_restore_early(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_restore_early) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_restore_early(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_suspend_noirq(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_suspend_noirq) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_suspend_noirq(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_resume_noirq(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_resume_noirq) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_resume_noirq(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_freeze_noirq(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_freeze_noirq) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_freeze_noirq(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_thaw_noirq(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_thaw_noirq) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_thaw_noirq(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_poweroff_noirq(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_poweroff_noirq) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_poweroff_noirq(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_pm_restore_noirq(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_pmops && coat_dev->osal_dev.osal_pmops->pm_restore_noirq) {
|
|
return coat_dev->osal_dev.osal_pmops->pm_restore_noirq(&(coat_dev->osal_dev));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_devfreq_target(struct media_device *media, unsigned long *freq, unsigned int flags)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_profile->target) {
|
|
return coat_dev->osal_dev.osal_profile->target(&(coat_dev->osal_dev), freq, flags);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_devfreq_get_dev_status(struct media_device *media, struct osal_devfreq_dev_status *stat)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_profile->get_dev_status) {
|
|
return coat_dev->osal_dev.osal_profile->get_dev_status(&(coat_dev->osal_dev), stat);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int osal_devfreq_get_cur_freq(struct media_device *media, unsigned long *freq)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
if (coat_dev->osal_dev.osal_profile->get_cur_freq) {
|
|
return coat_dev->osal_dev.osal_profile->get_cur_freq(&(coat_dev->osal_dev), freq);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void osal_devfreq_exit(struct media_device *media)
|
|
{
|
|
osal_coat_dev_t *coat_dev = container_of(media, struct osal_coat_dev, media_dev);
|
|
|
|
if (coat_dev->osal_dev.osal_profile->exit) {
|
|
return coat_dev->osal_dev.osal_profile->exit(&(coat_dev->osal_dev));
|
|
}
|
|
}
|
|
|
|
int osal_devfreq_register(osal_dev_t *osal_dev, struct osal_devfreq_dev_profile *osal_profile,
|
|
const char *governor, void *data)
|
|
{
|
|
struct media_device *media = NULL;
|
|
osal_devfreq_para_t devfreq_para = { 0 };
|
|
|
|
if ((osal_dev == NULL) || (osal_profile == NULL)) {
|
|
osal_printk("%s - parameter invalid!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
media = &(((osal_coat_dev_t *)(osal_dev->dev))->media_dev);
|
|
if ((governor != NULL) && (osal_strcmp(governor, "userspace") == 0)) {
|
|
osal_printk("Not supported governor\r\n");
|
|
return -1;
|
|
}
|
|
|
|
osal_dev->osal_profile = osal_profile;
|
|
|
|
devfreq_para.initial_freq = osal_dev->osal_profile->initial_freq;
|
|
devfreq_para.polling_ms = osal_dev->osal_profile->polling_ms;
|
|
devfreq_para.freq_table = osal_dev->osal_profile->freq_table;
|
|
devfreq_para.max_state = osal_dev->osal_profile->max_state;
|
|
|
|
return media_devfreq_register(media, &devfreq_para);
|
|
}
|
|
EXPORT_SYMBOL(osal_devfreq_register);
|
|
|
|
void osal_devfreq_unregister(osal_dev_t *osal_dev)
|
|
{
|
|
struct media_device *media = NULL;
|
|
|
|
if ((osal_dev == NULL) || (osal_dev->osal_profile == NULL)) {
|
|
osal_printk("%s - parameter invalid!\n", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
media = &(((osal_coat_dev_t *)(osal_dev->dev))->media_dev);
|
|
media_devfreq_unregister(media);
|
|
}
|
|
EXPORT_SYMBOL(osal_devfreq_unregister);
|
|
|
|
static struct media_ops s_osal_pmops = {
|
|
.pm_prepare = osal_pm_prepare,
|
|
.pm_complete = osal_pm_complete,
|
|
.pm_suspend = osal_pm_suspend,
|
|
.pm_resume = osal_pm_resume,
|
|
.pm_freeze = osal_pm_freeze,
|
|
.pm_thaw = osal_pm_thaw,
|
|
.pm_poweroff = osal_pm_poweroff,
|
|
.pm_restore = osal_pm_restore,
|
|
.pm_suspend_late = osal_pm_suspend_late,
|
|
.pm_resume_early = osal_pm_resume_early,
|
|
.pm_freeze_late = osal_pm_freeze_late,
|
|
.pm_thaw_early = osal_pm_thaw_early,
|
|
.pm_poweroff_late = osal_pm_poweroff_late,
|
|
.pm_restore_early = osal_pm_restore_early,
|
|
.pm_suspend_noirq = osal_pm_suspend_noirq,
|
|
.pm_resume_noirq = osal_pm_resume_noirq,
|
|
.pm_freeze_noirq = osal_pm_freeze_noirq,
|
|
.pm_thaw_noirq = osal_pm_thaw_noirq,
|
|
.pm_poweroff_noirq = osal_pm_poweroff_noirq,
|
|
.pm_restore_noirq = osal_pm_restore_noirq,
|
|
|
|
.devfreq_target = osal_devfreq_target,
|
|
.devfreq_get_dev_status = osal_devfreq_get_dev_status,
|
|
.devfreq_get_cur_freq = osal_devfreq_get_cur_freq,
|
|
.devfreq_exit = osal_devfreq_exit,
|
|
};
|
|
|
|
osal_dev_t *osal_createdev(const char *name)
|
|
{
|
|
osal_coat_dev_t *pdev = NULL;
|
|
if (name == NULL) {
|
|
osal_printk("%s - parameter invalid!\n", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
pdev = (osal_coat_dev_t *)kmalloc(sizeof(osal_coat_dev_t), GFP_KERNEL);
|
|
if (pdev == NULL) {
|
|
osal_printk("%s - kmalloc error!\n", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(pdev, 0, sizeof(osal_coat_dev_t));
|
|
osal_strncpy(pdev->osal_dev.name, name, sizeof(pdev->osal_dev.name) - 1);
|
|
pdev->osal_dev.dev = pdev;
|
|
return &(pdev->osal_dev);
|
|
}
|
|
EXPORT_SYMBOL(osal_createdev);
|
|
|
|
int osal_destroydev(osal_dev_t *osal_dev)
|
|
{
|
|
osal_coat_dev_t *pdev = NULL;
|
|
if (osal_dev == NULL) {
|
|
osal_printk("%s - parameter invalid!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
pdev = osal_dev->dev;
|
|
if (pdev == NULL) {
|
|
osal_printk("%s - parameter invalid!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
kfree(pdev);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(osal_destroydev);
|
|
|
|
int osal_registerdevice(osal_dev_t *osal_dev)
|
|
{
|
|
struct media_device *media = NULL;
|
|
if ((osal_dev == NULL) || (osal_dev->fops == NULL)) {
|
|
osal_printk("%s - parameter invalid!\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
media = &(((osal_coat_dev_t *)(osal_dev->dev))->media_dev);
|
|
if (osal_dev->minor != 0) {
|
|
media->minor = osal_dev->minor;
|
|
} else {
|
|
media->minor = MEDIA_DYNAMIC_MINOR;
|
|
}
|
|
media->owner = THIS_MODULE;
|
|
media->fops = &s_osal_fops;
|
|
media->drvops = &s_osal_pmops;
|
|
osal_strncpy(media->devfs_name, osal_dev->name, sizeof(media->devfs_name) - 1);
|
|
return media_register(media);
|
|
}
|
|
EXPORT_SYMBOL(osal_registerdevice);
|
|
|
|
void osal_deregisterdevice(osal_dev_t *pdev)
|
|
{
|
|
if (pdev == NULL) {
|
|
osal_printk("%s - parameter invalid!\n", __FUNCTION__);
|
|
return;
|
|
}
|
|
media_unregister((struct media_device *)&(((osal_coat_dev_t *)(pdev->dev))->media_dev));
|
|
}
|
|
EXPORT_SYMBOL(osal_deregisterdevice);
|
|
|
|
void osal_poll_wait(osal_poll_t *table, osal_wait_t *wait)
|
|
{
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - call poll_wait +!, table=%pK, file=%pK\n", __FUNCTION__, table->poll_table, table->data);
|
|
}
|
|
|
|
poll_wait ((struct file *)table->data, (wait_queue_head_t *)(wait->wait), table->poll_table);
|
|
|
|
if (DRVAL_DEBUG) {
|
|
osal_printk("%s - call poll_wait -!\n", __FUNCTION__);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(osal_poll_wait);
|
|
|
|
#if 0
|
|
void osal_pgprot_noncached(osal_vm_t *vm) {
|
|
struct vm_area_struct *v = (struct vm_area_struct *)(vm->vm);
|
|
v->vm_page_prot = pgprot_noncached(v->vm_page_prot);
|
|
}
|
|
#else
|
|
void osal_pgprot_noncached(osal_vm_t *vm)
|
|
{
|
|
struct vm_area_struct *v = (struct vm_area_struct *)(vm->vm);
|
|
v->vm_page_prot = pgprot_writecombine(v->vm_page_prot);
|
|
}
|
|
|
|
#endif
|
|
EXPORT_SYMBOL(osal_pgprot_noncached);
|
|
|
|
void osal_pgprot_cached(osal_vm_t *vm)
|
|
{
|
|
struct vm_area_struct *v = (struct vm_area_struct *)(vm->vm);
|
|
|
|
#ifdef CONFIG_64BIT
|
|
v->vm_page_prot = __pgprot(pgprot_val(v->vm_page_prot)
|
|
| PTE_VALID | PTE_DIRTY | PTE_AF);
|
|
#else
|
|
|
|
v->vm_page_prot = __pgprot(pgprot_val(v->vm_page_prot) | L_PTE_PRESENT
|
|
| L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_MT_DEV_CACHED);
|
|
#endif
|
|
}
|
|
EXPORT_SYMBOL(osal_pgprot_cached);
|
|
|
|
void osal_pgprot_writecombine(osal_vm_t *vm)
|
|
{
|
|
struct vm_area_struct *v = (struct vm_area_struct *)(vm->vm);
|
|
v->vm_page_prot = pgprot_writecombine(v->vm_page_prot);
|
|
}
|
|
EXPORT_SYMBOL(osal_pgprot_writecombine);
|
|
|
|
void osal_pgprot_stronglyordered(osal_vm_t *vm)
|
|
{
|
|
struct vm_area_struct *v = (struct vm_area_struct *)(vm->vm);
|
|
|
|
#ifdef CONFIG_64BIT
|
|
v->vm_page_prot = pgprot_device(v->vm_page_prot);
|
|
#else
|
|
v->vm_page_prot = pgprot_stronglyordered(v->vm_page_prot);
|
|
#endif
|
|
}
|
|
EXPORT_SYMBOL(osal_pgprot_stronglyordered);
|
|
|
|
int osal_remap_pfn_range(osal_vm_t *vm, unsigned long addr, unsigned long pfn, unsigned long size)
|
|
{
|
|
struct vm_area_struct *v = (struct vm_area_struct *)(vm->vm);
|
|
if (size == 0) {
|
|
return -EPERM;
|
|
}
|
|
return remap_pfn_range(v, addr, pfn, size, v->vm_page_prot);
|
|
}
|
|
EXPORT_SYMBOL(osal_remap_pfn_range);
|
|
|
|
int osal_io_remap_pfn_range(osal_vm_t *vm, unsigned long addr, unsigned long pfn, unsigned long size)
|
|
{
|
|
struct vm_area_struct *v = (struct vm_area_struct *)(vm->vm);
|
|
v->vm_flags |= VM_IO;
|
|
if (size == 0) {
|
|
return -EPERM;
|
|
}
|
|
return io_remap_pfn_range(v, addr, pfn, size, v->vm_page_prot);
|
|
}
|
|
EXPORT_SYMBOL(osal_io_remap_pfn_range);
|
|
|
|
#ifdef CONFIG_SNAPSHOT_BOOT
|
|
int osal_call_usermodehelper_force(char *path, char **argv, char **envp, int wait)
|
|
{
|
|
return call_usermodehelper_force(path, argv, envp, wait);
|
|
}
|
|
EXPORT_SYMBOL(osal_call_usermodehelper_force);
|
|
#endif
|