#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "almk_drv.h" /* #define USE_SYSRAM */ #define ALMK_MSG pr_debug #define ALMK_WRN pr_debug #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 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_MSG(KERN_ALERT "%s\n", __func__); ALMK_MSG(KERN_ALERT "=====================================\n"); for_each_process(p) { /* get_min_free_pages(p->pid); */ ALMK_MSG(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_MSG(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) { 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 const 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); 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 "); MODULE_DESCRIPTION("ALMK driver"); MODULE_LICENSE("GPL");