#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dispdev_drv.h" #include "dispdev_main.h" #include "dispdev_proc.h" #include "dispdev_dbg.h" //============================================================================= //Module parameter : Set module parameters when insert the module //============================================================================= #ifdef DEBUG unsigned int dispdev_debug_level = NVT_DBG_WRN; module_param_named(dispdev_debug_level, dispdev_debug_level, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(dispdev_debug_level, "Debug message level"); #endif EXPORT_SYMBOL(dispdev_debug_level); //============================================================================= // Global variable //============================================================================= static struct of_device_id dispdev_match_table[] = { { .compatible = "nvt,nvt_dispdev"}, {} }; //============================================================================= // function declaration //============================================================================= static int nvt_dispdev_open(struct inode *inode, struct file *file); static int nvt_dispdev_release(struct inode *inode, struct file *file); static long nvt_dispdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); static int nvt_dispdev_probe(struct platform_device *pdev); static int nvt_dispdev_suspend(struct platform_device *pdev, pm_message_t state); static int nvt_dispdev_resume(struct platform_device *pdev); static int nvt_dispdev_remove(struct platform_device *pdev); int __init nvt_dispdev_module_init(void); void __exit nvt_dispdev_module_exit(void); //============================================================================= // function define //============================================================================= static int nvt_dispdev_open(struct inode *inode, struct file *file) { DISPDEV_DRV_INFO *pdrv_info; pdrv_info = container_of(inode->i_cdev, DISPDEV_DRV_INFO, cdev); pdrv_info = container_of(inode->i_cdev, DISPDEV_DRV_INFO, cdev); file->private_data = pdrv_info; if (nvt_dispdev_drv_open(&pdrv_info->module_info, MINOR(inode->i_rdev))) { nvt_dbg(ERR, "failed to open driver\n"); return -1; } return 0; } static int nvt_dispdev_release(struct inode *inode, struct file *file) { DISPDEV_DRV_INFO *pdrv_info; pdrv_info = container_of(inode->i_cdev, DISPDEV_DRV_INFO, cdev); nvt_dispdev_drv_release(&pdrv_info->module_info, MINOR(inode->i_rdev)); return 0; } static long nvt_dispdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode; PDISPDEV_DRV_INFO pdrv; inode = file_inode(filp); pdrv = filp->private_data; return nvt_dispdev_drv_ioctl(MINOR(inode->i_rdev), &pdrv->module_info, cmd, arg); } struct file_operations nvt_dispdev_fops = { .owner = THIS_MODULE, .open = nvt_dispdev_open, .release = nvt_dispdev_release, .unlocked_ioctl = nvt_dispdev_ioctl, .llseek = no_llseek, }; static int nvt_dispdev_probe(struct platform_device *pdev) { DISPDEV_DRV_INFO *pdrv_info;//info; const struct of_device_id *match; int ret = 0; unsigned char ucloop; nvt_dbg(IND, "%s\n", pdev->name); match = of_match_device(dispdev_match_table, &pdev->dev); if (!match) { nvt_dbg(ERR, "Platform device not found \n"); return -EINVAL; } pdrv_info = kzalloc(sizeof(DISPDEV_DRV_INFO), GFP_KERNEL); if (!pdrv_info) { nvt_dbg(ERR, "failed to allocate memory\n"); return -ENOMEM; } /* for (ucloop = 0 ; ucloop < MODULE_REG_NUM ; ucloop++) { pdrv_info->presource[ucloop] = platform_get_resource(pdev, IORESOURCE_MEM, ucloop); if (pdrv_info->presource[ucloop] == NULL) { nvt_dbg(ERR, "No IO memory resource defined:%d\n", ucloop); ret = -ENODEV; goto FAIL_FREE_BUF; } } for (ucloop = 0 ; ucloop < MODULE_REG_NUM ; ucloop++) { nvt_dbg(IND, "%d. resource:0x%x size:0x%x\n", ucloop, pdrv_info->presource[ucloop]->start, resource_size(pdrv_info->presource[ucloop])); if (!request_mem_region(pdrv_info->presource[ucloop]->start, resource_size(pdrv_info->presource[ucloop]), pdev->name)) { nvt_dbg(ERR, "failed to request memory resource%d\n", ucloop); for (; ucloop > 0 ;) { ucloop -= 1; release_mem_region(pdrv_info->presource[ucloop]->start, resource_size(pdrv_info->presource[ucloop])); } ret = -ENODEV; goto FAIL_FREE_BUF; } } */ //Dynamic to allocate Device ID if (vos_alloc_chrdev_region(&pdrv_info->dev_id, MODULE_MINOR_COUNT, MODULE_NAME)) { nvt_dbg(ERR, "Can't get device ID\n"); ret = -ENODEV; goto FAIL_FREE_BUF; } nvt_dbg(IND, "dev_id Major:%d minor:%d\n" \ , MAJOR(pdrv_info->dev_id), MINOR(pdrv_info->dev_id)); /* Register character device for the volume */ cdev_init(&pdrv_info->cdev, &nvt_dispdev_fops); pdrv_info->cdev.owner = THIS_MODULE; if (cdev_add(&pdrv_info->cdev, pdrv_info->dev_id, MODULE_MINOR_COUNT)) { nvt_dbg(ERR, "Can't add cdev\n"); ret = -ENODEV; goto FAIL_CDEV; } pdrv_info->pmodule_class = class_create(THIS_MODULE, MODULE_NAME); if (IS_ERR(pdrv_info->pmodule_class)) { nvt_dbg(ERR, "failed in creating class.\n"); ret = -ENODEV; goto FAIL_CDEV; } /* register your own device in sysfs, and this will cause udev to create corresponding device node */ for (ucloop = 0 ; ucloop < (MODULE_MINOR_COUNT) ; ucloop++) { pdrv_info->pdevice[ucloop] = device_create(pdrv_info->pmodule_class, NULL , MKDEV(MAJOR(pdrv_info->dev_id), (ucloop + MINOR(pdrv_info->dev_id))), NULL , MODULE_NAME"%d", ucloop); if (IS_ERR(pdrv_info->pdevice[ucloop])) { nvt_dbg(ERR, "failed in creating device%d.\n", ucloop); #if (MODULE_REG_NUM > 1) for (; ucloop > 0 ; ucloop--) device_unregister(pdrv_info->pdevice[ucloop - 1]); #endif ret = -ENODEV; goto FAIL_CLASS; } } ret = nvt_dispdev_proc_init(pdrv_info); if (ret) { nvt_dbg(ERR, "failed in creating proc.\n"); goto FAIL_DEV; } ret = nvt_dispdev_drv_init(&pdrv_info->module_info); platform_set_drvdata(pdev, pdrv_info); if (ret) { nvt_dbg(ERR, "failed in creating proc.\n"); goto FAIL_DRV_INIT; } return ret; FAIL_DRV_INIT: nvt_dispdev_proc_remove(pdrv_info); FAIL_DEV: for (ucloop = 0 ; ucloop < (MODULE_MINOR_COUNT) ; ucloop++) { device_unregister(pdrv_info->pdevice[ucloop]); } FAIL_CLASS: class_destroy(pdrv_info->pmodule_class); FAIL_CDEV: cdev_del(&pdrv_info->cdev); vos_unregister_chrdev_region(pdrv_info->dev_id, MODULE_MINOR_COUNT); /* FAIL_FREE_RES: for (ucloop = 0 ; ucloop < MODULE_REG_NUM ; ucloop++) { release_mem_region(pdrv_info->presource[ucloop]->start, resource_size(pdrv_info->presource[ucloop])); } */ FAIL_FREE_BUF: kfree(pdrv_info); pdrv_info = NULL; platform_set_drvdata(pdev, pdrv_info); return ret; } static int nvt_dispdev_remove(struct platform_device *pdev) { PDISPDEV_DRV_INFO pdrv_info; unsigned char ucloop; nvt_dbg(IND, "\n"); pdrv_info = platform_get_drvdata(pdev); nvt_dispdev_drv_remove(&pdrv_info->module_info); nvt_dispdev_proc_remove(pdrv_info); for (ucloop = 0 ; ucloop < (MODULE_MINOR_COUNT) ; ucloop++) { device_unregister(pdrv_info->pdevice[ucloop]); } class_destroy(pdrv_info->pmodule_class); cdev_del(&pdrv_info->cdev); vos_unregister_chrdev_region(pdrv_info->dev_id, MODULE_MINOR_COUNT); /* for (ucloop = 0 ; ucloop < MODULE_REG_NUM ; ucloop++) { release_mem_region(pdrv_info->presource[ucloop]->start, resource_size(pdrv_info->presource[ucloop])); } */ kfree(pdrv_info); pdrv_info = NULL; platform_set_drvdata(pdev, pdrv_info); return 0; } static int nvt_dispdev_suspend(struct platform_device *pdev, pm_message_t state) { PDISPDEV_DRV_INFO pdrv_info;; nvt_dbg(IND, "start\n"); pdrv_info = platform_get_drvdata(pdev); nvt_dispdev_drv_suspend(&pdrv_info->module_info); nvt_dbg(IND, "finished\n"); return 0; } static int nvt_dispdev_resume(struct platform_device *pdev) { PDISPDEV_DRV_INFO pdrv_info;; nvt_dbg(IND, "start\n"); pdrv_info = platform_get_drvdata(pdev); nvt_dispdev_drv_resume(&pdrv_info->module_info); nvt_dbg(IND, "finished\n"); return 0; } static struct platform_driver nvt_dispdev_driver = { .driver = { .name = "nvt_dispdev", .owner = THIS_MODULE, .of_match_table = dispdev_match_table, }, .probe = nvt_dispdev_probe, .remove = nvt_dispdev_remove, .suspend = nvt_dispdev_suspend, .resume = nvt_dispdev_resume }; int __init nvt_dispdev_module_init(void) { int ret; nvt_dbg(WRN, "\n"); ret = platform_driver_register(&nvt_dispdev_driver); return 0; } void __exit nvt_dispdev_module_exit(void) { nvt_dbg(WRN, "\n"); platform_driver_unregister(&nvt_dispdev_driver); } module_init(nvt_dispdev_module_init); module_exit(nvt_dispdev_module_exit); MODULE_AUTHOR("Novatek Corp."); MODULE_DESCRIPTION("dispdev driver"); MODULE_LICENSE("GPL");