Consolodate and clean up device driver

This commit is contained in:
Roman Hargrave 2016-09-26 20:54:42 -05:00
parent 55b4930d5a
commit 7a6b72893e
2 changed files with 216 additions and 83 deletions

View File

@ -1,60 +1,78 @@
#include <linux/mm.h>
/*
* American Megatrends ROM Driver
* There wasn't a copyright here, so idk
*/
#include <asm/io.h>
#include <linux/version.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include "amifldrv.h"
#include "amiwrap.h"
int amifldrv_ioctl(void);
int amifldrv_mmap(void);
static int *kmalloc_area = NULL;
static int *kmalloc_ptr = NULL;
#include "linux_iface.h"
static int *kmalloc_area = NULL;
static int *kmalloc_ptr = NULL;
static unsigned long kmalloc_len = 0L;
static int kcount = 0;
static int major;
static AMIFLDRV_ALLOC kmalloc_drv[128];
static int kcount = 0;
static int amifldrv_init_module(void)
/*
* Section: Character Device Implementation
* ============================================================================
*/
#if LINUX_POST_2_6
static int chardev_open_count = 0;
#endif
/**
* Character Device open action
*/
int
AMI_chrdrv_open(struct inode* inode, struct file* file)
{
ulArg0 = 0;
pvArg0 = &amifldrv_fops;
if ((major=wrap_register_chrdev()) < 0) {
return (-EIO);
#if LINUX_PRE_2_6
MOD_INC_USE_COUNT;
#else
if (chardev_open_count > 0)
{
return -EBUSY;
}
memset(kmalloc_drv, 0, sizeof(AMIFLDRV_ALLOC) * 128);
++chardev_open_count;
try_module_get(THIS_MODULE);
#endif
return(0);
}
static void amifldrv_cleanup_module(void)
int
AMI_chrdrv_release(struct inode* inode, struct file* file)
{
unsigned long virt_addr;
int iloop = 0;
if (kcount > 0) {
for (iloop=0; iloop<kcount; iloop++) {
kmalloc_ptr = kmalloc_drv[iloop].kmallocptr;
kmalloc_area = kmalloc_drv[iloop].kvirtadd;
kmalloc_len = kmalloc_drv[iloop].kvirtlen;
if (kmalloc_ptr) {
for(virt_addr=(unsigned long)kmalloc_area; virt_addr<(unsigned long)kmalloc_area+kmalloc_len; virt_addr+=PAGE_SIZE) {
ulArg0 = virt_addr;
pvArg0 = wrap_virt_to_page();
wrap_mem_map_unreserve();
}
if (kmalloc_ptr) {
pvArg0 = kmalloc_ptr;
wrap_kfree();
}
}
}
kcount = 0;
}
ulArg0 = major;
wrap_unregister_chrdev();
return;
#if LINUX_PRE_2_6
MOD_DEC_USE_COUNT;
#else
--chardev_open_count;
module_put(THIS_MODULE);
#endif
return(0);
}
module_init(amifldrv_init_module);
module_exit(amifldrv_cleanup_module);
int amifldrv_ioctl(void)
#if defined(HAVE_UNLOCKED_IOCTL)
long
AMI_chrdrv_ioctl(struct file* _unused_file, unsigned int cmd, unsigned long arg)
#else
int
AMI_chrdrv_ioctl(struct inode* _unused_inode, unsigned int cmd, unsigned long arg)
#endif
{
unsigned int cmd = (unsigned int)ulArg0;
unsigned long arg = ulArg1;
switch(cmd)
{
case CMD_ALLOC:
@ -62,26 +80,33 @@ int amifldrv_ioctl(void)
int i;
unsigned long virt_addr;
AMIFLDRV_ALLOC arg_kernel_space;
if (kcount >= 128) return -EINVAL;
kmalloc_ptr = NULL;
if (!arg || kmalloc_ptr) {
if (kcount >= 128)
{
return -EINVAL;
}
pvArg0 = (void*)&arg_kernel_space;
pvArg1 = (void*)arg;
ulArg0 = sizeof(AMIFLDRV_ALLOC);
wrap_copy_from_user();
if (arg_kernel_space.size > 128*1024) return -EINVAL;
kmalloc_ptr = NULL;
if (!arg || kmalloc_ptr)
{
return -EINVAL;
}
copy_from_user((void*) &arg_kernel_space, (void*) arg, sizeof(AMIFLDRV_ALLOC));
if (arg_kernel_space.size > 128*1024)
{
return -EINVAL;
}
kmalloc_len = ((arg_kernel_space.size + PAGE_SIZE -1) & PAGE_MASK);
ulArg0 = kmalloc_len+2*PAGE_SIZE;
ulArg1 = GFP_DMA|GFP_KERNEL;
kmalloc_ptr = wrap_kmalloc();
kmalloc_ptr = kmalloc((kmalloc_len + 2 * PAGE_SIZE), GFP_DMA | GFP_KERNEL);
kmalloc_area=(int *)(((unsigned long)kmalloc_ptr + PAGE_SIZE -1) & PAGE_MASK);
for (virt_addr=(unsigned long)kmalloc_area; virt_addr<(unsigned long)kmalloc_area+kmalloc_len; virt_addr+=PAGE_SIZE)
{
ulArg0 = virt_addr;
pvArg0 = wrap_virt_to_page();
wrap_mem_map_reserve();
mem_map_reserve(virt_to_page(virt_addr));
}
for (i=0; i<(kmalloc_len/sizeof(int)); i++) {
kmalloc_area[i]=(0xafd0<<16) +i;
@ -94,10 +119,9 @@ int amifldrv_ioctl(void)
kcount++;
arg_kernel_space.kvirtadd = kmalloc_area;
arg_kernel_space.kphysadd = (void *)((unsigned long)virt_to_phys(kmalloc_area));
pvArg0 = (void*)arg;
pvArg1 = (void*)&arg_kernel_space;
ulArg0 = sizeof(AMIFLDRV_ALLOC);
wrap_copy_to_user();
copy_to_user((void*) arg, (void*) &arg_kernel_space, sizeof(AMIFLDRV_ALLOC));
return 0;
}
case CMD_FREE:
@ -105,10 +129,9 @@ int amifldrv_ioctl(void)
unsigned long virt_addr;
AMIFLDRV_ALLOC arg_kernel_space;
int isearch = 0;
pvArg0 = (void*)&arg_kernel_space;
pvArg1 = (void*)arg;
ulArg0 = sizeof(AMIFLDRV_ALLOC);
wrap_copy_from_user();
copy_from_user((void*) &arg_kernel_space, (void*) arg, sizeof(AMIFLDRV_ALLOC));
if (kcount > 0) {
for (isearch=0; isearch<kcount; isearch++) {
if (kmalloc_drv[isearch].kphysadd == arg_kernel_space.kphysadd) break;
@ -122,13 +145,10 @@ int amifldrv_ioctl(void)
if (kmalloc_ptr) {
for(virt_addr=(unsigned long)kmalloc_area; virt_addr<(unsigned long)kmalloc_area+kmalloc_len; virt_addr+=PAGE_SIZE)
{
ulArg0 = virt_addr;
pvArg0 = wrap_virt_to_page();
wrap_mem_map_unreserve();
mem_map_unreserve(virt_to_page(virt_addr));
}
if (kmalloc_ptr) {
pvArg0 = kmalloc_ptr;
wrap_kfree();
kfree(kmalloc_ptr);
}
kmalloc_len = 0L;
kmalloc_ptr = NULL;
@ -158,34 +178,136 @@ int amifldrv_ioctl(void)
}
return -ENOTTY;
}
int amifldrv_mmap(void)
int
AMI_chrdrv_mmap(struct file* file, struct vm_area_struct* vma)
{
struct vm_area_struct *vma = (struct vm_area_struct *)pvArg1;
unsigned long offset = vma->vm_pgoff<<PAGE_SHIFT;
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long size = vma->vm_end - vma->vm_start;
if (offset & ~PAGE_MASK) {
return -ENXIO;
}
if (!kmalloc_ptr) {
return(-ENXIO);
}
if (size>kmalloc_len) {
if (size > kmalloc_len) {
return(-ENXIO);
}
if ((offset+size)>kmalloc_len) {
if ((offset+size) > kmalloc_len) {
return -ENXIO;
}
if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) {
return(-EINVAL);
}
vma->vm_flags |= VM_LOCKED;
pvArg0 = vma;
ulArg0 = vma->vm_start;
ulArg1 = virt_to_phys((void*)((unsigned long)kmalloc_area));
ulArg2 = size;
pgArg0 = PAGE_SHARED;
if (wrap_remap_page_range()) {
return -ENXIO;
{
unsigned long pfn = virt_to_phys((void*)((unsigned long) kmalloc_area));
#if LINUX_POST_2_6
int remap_result =
remap_pfn_range(vma,
vma->vm_start,
pfn >> PAGE_SHIFT,
size,
PAGE_SHARED);
#else
int remap_result =
remap_page_range(vma,
vma->vm_start,
pfn,
size,
PAGE_SHARED);
#endif
if (remap_result)
{
return -ENXIO;
}
}
return(0);
}
#if defined(HAVE_UNLOCKED_IOCTL)
# define $IOCTL_FIELD unlocked_ioctl
#else
# define $IOCTL_FIELD ioctl
#endif
struct file_operations AMI_chrdrv_fops = {
owner: THIS_MODULE,
open: AMI_chrdrv_open,
release: AMI_chrdrv_release,
mmap: AMI_chrdrv_mmap,
$IOCTL_FIELD: AMI_chrdrv_ioctl,
};
/*
* Section: Linux Kernel Module Setup
* ============================================================================
*/
#if LINUX_POST_2_6
MODULE_AUTHOR ("American Megatrends Inc.");
MODULE_DESCRIPTION ("AMI Flash Update utility driver");
MODULE_LICENSE ("Proprietary");
#endif
static int /* module_init */
amifldrv_init_module(void)
{
major = register_chrdev(0, "amifldrv", &AMI_chrdrv_fops);
if (major < 0)
{
return -EIO;
}
memset(kmalloc_drv, 0, sizeof(AMIFLDRV_ALLOC) * 128);
return(0);
}
static void /* module_exit */
amifldrv_cleanup_module(void)
{
unsigned long virt_addr;
int iloop = 0;
if (kcount > 0)
{
for (iloop=0; iloop < kcount; iloop++)
{
kmalloc_ptr = kmalloc_drv[iloop].kmallocptr;
kmalloc_area = kmalloc_drv[iloop].kvirtadd;
kmalloc_len = kmalloc_drv[iloop].kvirtlen;
if (kmalloc_ptr)
{
for(virt_addr = (unsigned long)kmalloc_area;
virt_addr < (unsigned long)kmalloc_area + kmalloc_len;
virt_addr += PAGE_SIZE)
{
mem_map_unreserve(virt_to_page(virt_addr));
}
if (kmalloc_ptr)
{
kfree(kmalloc_ptr);
}
}
}
kcount = 0;
}
unregister_chrdev(major, "amifldrv");
return;
}
module_init(amifldrv_init_module);
module_exit(amifldrv_cleanup_module);

11
linux_iface.h Normal file
View File

@ -0,0 +1,11 @@
#include <linux/version.h>
#define LINUX_PRE_2_6 (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
#define LINUX_POST_2_6 (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
#if LINUX_PRE_2_6
# include <linux/wrapper.h>
#else
# define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))
# define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags))
#endif