blob: 141dbe79012b95a01279a49ee2cd83d5f93ec501 [file] [log] [blame]
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/module.h>
#include <generated/autoconf.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/param.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/xlog.h>
#include <asm/io.h>
#include "almk_drv.h"
#define pr_fmt(fmt) "["KBUILD_MODNAME"]"fmt
#include <linux/module.h>
/* #define USE_SYSRAM */
/* #define ALMK_MSG(...) xlog_printk(ANDROID_LOG_DEBUG, "xlog/almk", __VA_ARGS__) */
/* #define ALMK_WRN(...) xlog_printk(ANDROID_LOG_WARN, "xlog/almk", __VA_ARGS__) */
/* #define ALMK_ERR(...) xlog_printk(ANDROID_LOG_ERROR, "xlog/almk", __VA_ARGS__) */
#define ALMK_MSG pr_debug
#define ALMK_WRN pr_warning
#define ALMK_ERR pr_err
#define ALMK_DEVNAME "mtk_almk"
#define ALMK_PROCESS 0x2
/* -------------------------------------------------------------------------- */
/* */
/* -------------------------------------------------------------------------- */
/* global function */
static unsigned int _almk_int_status;
/* device and driver */
static dev_t almk_devno;
static struct cdev *almk_cdev;
static struct class *almk_class;
/* static wait_queue_head_t enc_wait_queue; */
static spinlock_t almk_lock;
static int almk_status;
#if 0
static int check_all_minfree(void *param, void *param2)
{
#if 1
extern int get_min_free_pages(pid_t pid);
struct task_struct *p = 0;
int n = 4096 * 170000;
int nr_pages = (n / PAGE_SIZE) + ((n % PAGE_SIZE) ? 1 : 0);
int free_pages = global_page_state(NR_FREE_PAGES) +
global_page_state(NR_FILE_PAGES) + global_page_state(NR_FILE_DIRTY);
ALMK_WRN(KERN_ALERT "%s\n", __func__);
ALMK_WRN(KERN_ALERT "=====================================\n");
for_each_process(p) {
/* get_min_free_pages(p->pid); */
ALMK_WRN(KERN_ALERT "trying to alloc %d bytes (%d pages)\n"
"(NR_FREE_PAGES) + "
"(NR_FILE_PAGES) + "
"(NR_FILE_DIRTY) - "
"nr_pages = (%d + %d + %d - %d) = %d\n"
"target_min_free_pages = %d\n",
n, nr_pages,
global_page_state(NR_FREE_PAGES),
global_page_state(NR_FILE_PAGES),
global_page_state(NR_FILE_DIRTY),
nr_pages, free_pages - nr_pages, get_min_free_pages(p->pid));
ALMK_WRN(KERN_ALERT "allocation is %s\n",
(free_pages - nr_pages >= get_min_free_pages(p->pid)) ?
"safe" : "not safe");
}
#endif
}
#endif
static unsigned int get_max_safe_size(pid_t pid)
{
extern int get_min_free_pages(pid_t pid);
extern int query_lmk_minfree(int index);
unsigned int all_free_pages;
unsigned int lmk_pages;
unsigned int lowBoundPages = get_min_free_pages(pid);
unsigned int max_safe_size;
lmk_pages = query_lmk_minfree(0);
all_free_pages = global_page_state(NR_FREE_PAGES) +
global_page_state(NR_FILE_PAGES) + global_page_state(NR_FILE_DIRTY);
if (all_free_pages >= (lowBoundPages + lmk_pages)) {
max_safe_size = (all_free_pages - lowBoundPages - lmk_pages) * PAGE_SIZE;
} else if (all_free_pages >= (lowBoundPages)) {
max_safe_size = (all_free_pages - lowBoundPages) * PAGE_SIZE;
} else
return 0;
return max_safe_size;
}
static int almk_ioctl(unsigned int cmd, unsigned long arg, struct file *file)
{
ALMK_DRV_DATA drv_data;
unsigned int max_safe_size;
unsigned int *pStatus;
pStatus = (unsigned int *)file->private_data;
if (NULL == pStatus) {
ALMK_WRN("Private data is null in flush operation. HOW COULD THIS HAPPEN ??\n");
return -EFAULT;
}
switch (cmd) {
/* initial and reset ALMK */
case ALMK_IOCTL_CMD_INIT:
ALMK_MSG("ALMK Driver Initial and Lock\n");
*pStatus = ALMK_PROCESS;
break;
case ALMK_IOCTL_CMD_GET_MAX_SIZE:
ALMK_MSG("ALMK Driver GET_MAX_SIZE!!\n");
if (*pStatus != ALMK_PROCESS) {
ALMK_WRN("Permission Denied! This process can not access ALMK Driver");
return -EFAULT;
}
if (copy_from_user(&drv_data, (void *)arg, sizeof(ALMK_DRV_DATA))) {
ALMK_WRN("ALMK Driver : Copy from user error\n");
return -EFAULT;
}
max_safe_size = get_max_safe_size(drv_data.pid);
if (copy_to_user(drv_data.maxSafeSize, &max_safe_size, sizeof(unsigned int))) {
ALMK_WRN("ALMK Driver : Copy to user error (result)\n");
return -EFAULT;
}
break;
case ALMK_IOCTL_CMD_DEINIT:
/* copy input parameters */
ALMK_MSG("ALMK Driver Deinit!!\n");
if (*pStatus != ALMK_PROCESS) {
ALMK_WRN("Permission Denied! This process can not access ALMK Driver");
return -EFAULT;
}
*pStatus = 0;
return 0;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* */
/* -------------------------------------------------------------------------- */
/* static int almk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) */
static long almk_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case ALMK_IOCTL_CMD_INIT:
case ALMK_IOCTL_CMD_GET_MAX_SIZE:
case ALMK_IOCTL_CMD_DEINIT:
return almk_ioctl(cmd, arg, file);
default:
break;
}
return -EINVAL;
}
static int almk_open(struct inode *inode, struct file *file)
{
unsigned int *pStatus;
/* Allocate and initialize private data */
file->private_data = kmalloc(sizeof(unsigned int), GFP_ATOMIC);
if (NULL == file->private_data) {
ALMK_WRN("Not enough entry for ALMK open operation\n");
return -ENOMEM;
}
pStatus = (unsigned int *)file->private_data;
*pStatus = 0;
return 0;
}
static ssize_t almk_read(struct file *file, char __user *data, size_t len, loff_t *ppos)
{
ALMK_MSG("almk driver read\n");
return 0;
}
static int almk_release(struct inode *inode, struct file *file)
{
if (NULL != file->private_data) {
kfree(file->private_data);
file->private_data = NULL;
}
return 0;
}
static int almk_flush(struct file *a_pstFile, fl_owner_t a_id)
{
unsigned int *pStatus;
pStatus = (unsigned int *)a_pstFile->private_data;
if (NULL == pStatus) {
ALMK_WRN("Private data is null in flush operation. HOW COULD THIS HAPPEN ??\n");
return -EFAULT;
}
return 0;
}
/* Kernel interface */
static struct file_operations almk_fops = {
.owner = THIS_MODULE,
/* .ioctl = almk_ioctl, */
.unlocked_ioctl = almk_unlocked_ioctl,
.open = almk_open,
.release = almk_release,
.flush = almk_flush,
.read = almk_read,
};
static int almk_probe(struct platform_device *pdev)
{
struct class_device;
int ret;
struct class_device *class_dev = NULL;
ALMK_MSG("-------------almk driver probe-------\n");
ret = alloc_chrdev_region(&almk_devno, 0, 1, ALMK_DEVNAME);
if (ret) {
ALMK_ERR("Error: Can't Get Major number for ALMK Device\n");
} else {
ALMK_MSG("Get ALMK Device Major number (%d)\n", almk_devno);
}
almk_cdev = cdev_alloc();
almk_cdev->owner = THIS_MODULE;
almk_cdev->ops = &almk_fops;
ret = cdev_add(almk_cdev, almk_devno, 1);
almk_class = class_create(THIS_MODULE, ALMK_DEVNAME);
class_dev =
(struct class_device *)device_create(almk_class, NULL, almk_devno, NULL, ALMK_DEVNAME);
spin_lock_init(&almk_lock);
/* initial driver, register driver ISR */
almk_status = 0;
_almk_int_status = 0;
ALMK_MSG("ALMK Probe Done\n");
/* NOT_REFERENCED(class_dev); */
return 0;
}
static int almk_remove(struct platform_device *pdev)
{
ALMK_MSG("ALMK driver remove\n");
ALMK_MSG("Done\n");
return 0;
}
static void almk_shutdown(struct platform_device *pdev)
{
ALMK_MSG("ALMK driver shutdown\n");
/* Nothing yet */
}
/* PM suspend */
static int almk_suspend(struct platform_device *pdev, pm_message_t mesg)
{
/* almk_drv_dec_deinit(); */
/* almk_drv_enc_deinit(); */
return 0;
}
/* PM resume */
static int almk_resume(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver almk_driver = {
.probe = almk_probe,
.remove = almk_remove,
.shutdown = almk_shutdown,
.suspend = almk_suspend,
.resume = almk_resume,
.driver = {
.name = ALMK_DEVNAME,
},
};
static void almk_device_release(struct device *dev)
{
/* Nothing to release? */
}
static u64 jpegdec_dmamask = ~(u32) 0;
static struct platform_device almk_device = {
.name = ALMK_DEVNAME,
.id = 0,
.dev = {
.release = almk_device_release,
.dma_mask = &jpegdec_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = 0,
};
static int __init almk_init(void)
{
int ret;
ALMK_MSG("ALMK driver initialize\n");
ALMK_MSG("Register the ALMK driver device\n");
if (platform_device_register(&almk_device)) {
ALMK_ERR("failed to register jpeg driver device\n");
ret = -ENODEV;
return ret;
}
ALMK_MSG("Register the ALMK driver\n");
if (platform_driver_register(&almk_driver)) {
ALMK_ERR("failed to register jpeg driver\n");
platform_device_unregister(&almk_device);
ret = -ENODEV;
return ret;
}
return 0;
}
static void __exit almk_exit(void)
{
cdev_del(almk_cdev);
unregister_chrdev_region(almk_devno, 1);
/* ALMK_MSG("Unregistering driver\n"); */
platform_driver_unregister(&almk_driver);
platform_device_unregister(&almk_device);
device_destroy(almk_class, almk_devno);
class_destroy(almk_class);
ALMK_MSG("Done\n");
}
module_init(almk_init);
module_exit(almk_exit);
MODULE_AUTHOR("Otis, Huang <otis.huang@mediatek.com>");
MODULE_DESCRIPTION("ALMK driver");
MODULE_LICENSE("GPL");