Add code
This commit is contained in:
parent
a205a83ae5
commit
3f5e410e71
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# Makefile for InsydeFlash tool for Linux (build your main kernel)
|
||||
#
|
||||
MACHINE = $(shell uname -m)
|
||||
|
||||
obj-m+=isfl_drv.o
|
||||
|
||||
|
||||
all: isfl_drv
|
||||
|
||||
isfl_drv:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* InsydeFlash Linux Driver
|
||||
* File: isfl.h
|
||||
*
|
||||
* Copyright (C) 2005 - 2015 Insyde Software Corp.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#define DEVICE_NAME "isfl" //InsydeFlash buffer
|
||||
#define DEVICE_NAME_PATH "/dev/"DEVICE_NAME // Open device node on user-space
|
||||
#define DEVICE_MAJOR_NUM 100
|
||||
#define ISFB_FLASH_SIZE ( 128 * 1024 ) // 128KB
|
||||
#define MEMORY_BLOCK_SIZE ( 64 * 1024 ) // 64KB
|
||||
#define MAX_MEMORY_BLOCK_COUNT 512
|
||||
|
||||
struct _isfl
|
||||
{
|
||||
unsigned long smi_io; // SMI Port
|
||||
unsigned long mbuf_size; // memory buffer size
|
||||
unsigned long mbuf_paddr; // memory buffer physical address
|
||||
unsigned long smi_status; // SW SMI Status Return
|
||||
unsigned long enable_kbc;
|
||||
unsigned long disable_kbc;
|
||||
};
|
||||
|
||||
struct _mblock
|
||||
{
|
||||
unsigned long mbuf_PhyAddr; // memory buffer index
|
||||
unsigned long mbuf_size; // memory buffer size
|
||||
unsigned char pbyBuffer[MEMORY_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
#define IOCTL_ALLOCATE_MEMORY _IOWR(DEVICE_MAJOR_NUM, 0, struct _isfl *)
|
||||
#define IOCTL_FREE_MEMORY _IOW(DEVICE_MAJOR_NUM, 1, struct _isfl *)
|
||||
#define IOCTL_WRITE_MEMORY _IOWR(DEVICE_MAJOR_NUM, 2, struct _isfl *)
|
||||
#define IOCTL_READ_MEMORY _IOWR(DEVICE_MAJOR_NUM, 3, struct _isfl *)
|
||||
#define IOCTL_GENERATE_SMI _IOW(DEVICE_MAJOR_NUM, 4, struct _isfl *)
|
||||
#define IOCTL_GET_SMI_STATUS _IOR(DEVICE_MAJOR_NUM, 5, struct _isfl *)
|
||||
#define IOCTL_DISABLE_KBC _IOR(DEVICE_MAJOR_NUM, 6, struct _isfl *)
|
||||
#define IOCTL_ENABLE_KBC _IOR(DEVICE_MAJOR_NUM, 7, struct _isfl *)
|
||||
#define IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY _IOWR(DEVICE_MAJOR_NUM, 8, struct _isfl *)
|
||||
#define IOCTL_FREE_MULTI_BLOCK_MEMORY _IOW(DEVICE_MAJOR_NUM, 9, struct _isfl *)
|
||||
#define IOCTL_WRITE_TO_PHYSICAL _IOWR(DEVICE_MAJOR_NUM, 10, struct _mblock *)
|
||||
#define IOCTL_READ_FROME_PHYSICAL _IOWR(DEVICE_MAJOR_NUM, 11, struct _mblock *)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,558 @@
|
|||
/*
|
||||
* InsydeFlash Linux Driver
|
||||
* File: isfl_drv.c
|
||||
*
|
||||
* Copyright (C) 2005 - 2015 Insyde Software Corp.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/version.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
typedef struct _PageAlloc {
|
||||
unsigned long addr;
|
||||
unsigned long PhyAddr;
|
||||
unsigned int order;
|
||||
}PageAlloc_t;
|
||||
|
||||
#include "isfl.h"
|
||||
|
||||
#define MAX_8042_LOOPS 100000
|
||||
|
||||
#define ISFL_VERSION "0.0.05"
|
||||
#define DRIVER_AUTHOR "Howard Ho <howard.ho@insydesw.com.tw>"
|
||||
#define DRIVER_DESC "InsydeFlash tool for Linux"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
static dev_t first;
|
||||
static struct cdev c_dev;
|
||||
static struct class *isfl_class;
|
||||
#endif
|
||||
|
||||
static int Device_Open = 0;
|
||||
static unsigned char *isfl_mem_buff;
|
||||
static unsigned char *g_ppbyMemoryBuffer[MAX_MEMORY_BLOCK_COUNT] = {0};
|
||||
static PageAlloc_t g_ppbyMemoryBuffer2[MAX_MEMORY_BLOCK_COUNT] = {{0,0}};
|
||||
static int isfl_open(struct inode *, struct file *);
|
||||
static int isfl_release(struct inode *, struct file *);
|
||||
static ssize_t isfl_read(struct file *, char *, size_t, loff_t *);
|
||||
static ssize_t isfl_write(struct file *file, const char *buff, size_t length, loff_t *offset);
|
||||
//Flash will close kbc except show dialog
|
||||
static void enable_a20_kbc(void);
|
||||
static void disable_a20_kbc(void);
|
||||
//static int empty_8042(void);
|
||||
static inline void io_delay(void);
|
||||
|
||||
//Use this function to get the message from AP
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
static long isfl_ioctl(struct file *file, unsigned int num, unsigned long arg)
|
||||
#else
|
||||
static int isfl_ioctl(struct inode *inode, struct file *file, unsigned int num, unsigned long arg)
|
||||
#endif
|
||||
{
|
||||
unsigned long isfl_phys_addr; // Assgin to SW SMI
|
||||
struct _isfl *isfl;
|
||||
int isfl_size = sizeof( struct _isfl );
|
||||
unsigned char buf[isfl_size];
|
||||
struct _mblock *pBlock;
|
||||
int iBlockStructureSize = sizeof( struct _mblock );
|
||||
unsigned char *pbyBlockBuffer;
|
||||
unsigned char *ch;
|
||||
int i;
|
||||
unsigned long mbuf_index;
|
||||
unsigned char *vir_addr = 0;
|
||||
|
||||
switch ( num )
|
||||
{
|
||||
case IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY:
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
isfl = (struct _isfl *)buf;
|
||||
|
||||
mbuf_index = isfl->mbuf_paddr; // use mbuf_paddr to store mbuf_index to backward compatible
|
||||
|
||||
// Allocate memory buffer
|
||||
g_ppbyMemoryBuffer2[mbuf_index].order = get_order( isfl->mbuf_size );
|
||||
g_ppbyMemoryBuffer2[mbuf_index].addr = __get_free_pages( GFP_DMA32, g_ppbyMemoryBuffer2[mbuf_index].order );
|
||||
g_ppbyMemoryBuffer[mbuf_index] = (unsigned char *)g_ppbyMemoryBuffer2[mbuf_index].addr;
|
||||
if ( g_ppbyMemoryBuffer[mbuf_index] == NULL )
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY allocate physical memory failed\n" );
|
||||
return -1;
|
||||
}
|
||||
memset( g_ppbyMemoryBuffer[mbuf_index], 0, isfl->mbuf_size );
|
||||
|
||||
g_ppbyMemoryBuffer2[mbuf_index].PhyAddr = virt_to_phys( g_ppbyMemoryBuffer[mbuf_index] );
|
||||
isfl->mbuf_paddr = g_ppbyMemoryBuffer2[mbuf_index].PhyAddr;
|
||||
//printk( KERN_INFO "isfl alloc id=%d, PhyAddr=%x\n", mbuf_index, g_ppbyMemoryBuffer2[mbuf_index].PhyAddr );
|
||||
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
put_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case IOCTL_FREE_MULTI_BLOCK_MEMORY:
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
isfl = (struct _isfl *)buf;
|
||||
|
||||
mbuf_index = -1;
|
||||
isfl_phys_addr = isfl->mbuf_paddr;
|
||||
for (i = 0; i < MAX_MEMORY_BLOCK_COUNT; i++)
|
||||
if (isfl_phys_addr == g_ppbyMemoryBuffer2[i].PhyAddr)
|
||||
mbuf_index = i;
|
||||
if (-1 == mbuf_index)
|
||||
return -1;
|
||||
|
||||
// Free Memory
|
||||
if ( g_ppbyMemoryBuffer[mbuf_index] != NULL )
|
||||
{
|
||||
free_pages( g_ppbyMemoryBuffer2[mbuf_index].addr, g_ppbyMemoryBuffer2[mbuf_index].order );
|
||||
g_ppbyMemoryBuffer2[mbuf_index].addr = 0;
|
||||
g_ppbyMemoryBuffer2[mbuf_index].order = 0;
|
||||
g_ppbyMemoryBuffer[mbuf_index] = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case IOCTL_WRITE_TO_PHYSICAL:
|
||||
ch = (unsigned char *)arg;
|
||||
pbyBlockBuffer = kmalloc( iBlockStructureSize, GFP_DMA );
|
||||
if ( pbyBlockBuffer == NULL )
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_WRITE_TO_PHYSICAL with NULL parameter\n" );
|
||||
return -1;
|
||||
}
|
||||
for ( i = 0; i < iBlockStructureSize; i++ )
|
||||
{
|
||||
get_user( pbyBlockBuffer[i], ( ch + i ) );
|
||||
}
|
||||
pBlock = (struct _mblock *)pbyBlockBuffer;
|
||||
isfl_phys_addr = pBlock->mbuf_PhyAddr;
|
||||
//printk( KERN_INFO "isfl write PhyAddr=%x\n", pBlock->mbuf_PhyAddr);
|
||||
//printk( KERN_INFO "isfl write len=%x\n", pBlock->mbuf_size);
|
||||
//printk( KERN_INFO "isfl write PhyAddr=%x\n", isfl_phys_addr );
|
||||
|
||||
mbuf_index = -1;
|
||||
for (i = 0; i < MAX_MEMORY_BLOCK_COUNT; i++)
|
||||
if (isfl_phys_addr == g_ppbyMemoryBuffer2[i].PhyAddr)
|
||||
mbuf_index = i;
|
||||
if (-1 == mbuf_index)
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_WRITE_TO_PHYSICAL with wrong physcial address\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( g_ppbyMemoryBuffer[mbuf_index] == NULL )
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_WRITE_TO_PHYSICAL with physcial address didn't allocate\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( i = 0; i < pBlock->mbuf_size && i < ISFB_FLASH_SIZE; i++ )
|
||||
{
|
||||
g_ppbyMemoryBuffer[mbuf_index][i] = pBlock->pbyBuffer[i];
|
||||
}
|
||||
|
||||
kfree( pbyBlockBuffer );
|
||||
break;
|
||||
|
||||
case IOCTL_READ_FROME_PHYSICAL:
|
||||
ch = (unsigned char *)arg;
|
||||
pbyBlockBuffer = kmalloc( iBlockStructureSize, GFP_DMA );
|
||||
if ( pbyBlockBuffer == NULL )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for ( i = 0; i < iBlockStructureSize; i++ )
|
||||
{
|
||||
get_user( pbyBlockBuffer[i], ( ch + i ) );
|
||||
}
|
||||
pBlock = (struct _mblock *)pbyBlockBuffer;
|
||||
isfl_phys_addr = pBlock->mbuf_PhyAddr;
|
||||
//printk( KERN_INFO "isfl read PhyAddr=%x\n", pBlock->mbuf_PhyAddr);
|
||||
//printk( KERN_INFO "isfl read len=%x\n", pBlock->mbuf_size);
|
||||
//printk( KERN_INFO "isfl read PhyAddr=%x\n", isfl_phys_addr );
|
||||
|
||||
mbuf_index = -1;
|
||||
for (i = 0; i < MAX_MEMORY_BLOCK_COUNT; i++)
|
||||
if (isfl_phys_addr == g_ppbyMemoryBuffer2[i].PhyAddr)
|
||||
mbuf_index = i;
|
||||
if (-1 == mbuf_index)
|
||||
return -1;
|
||||
|
||||
if ( g_ppbyMemoryBuffer[mbuf_index] == NULL )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( i = 0; i < pBlock->mbuf_size && i < ISFB_FLASH_SIZE; i++ )
|
||||
{
|
||||
pBlock->pbyBuffer[i] = g_ppbyMemoryBuffer[mbuf_index][i];
|
||||
}
|
||||
|
||||
for ( i = 0; i < iBlockStructureSize; i++ )
|
||||
{
|
||||
put_user( pbyBlockBuffer[i], ( ch + i ) );
|
||||
}
|
||||
kfree( pbyBlockBuffer );
|
||||
break;
|
||||
|
||||
case IOCTL_ALLOCATE_MEMORY:
|
||||
//printk( KERN_INFO "IOCTL_ALLOCATE_MEMORY\n" );
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
//printk( KERN_INFO "%02X ", buf[i] );
|
||||
}
|
||||
//printk( KERN_INFO "\n" );
|
||||
isfl = (struct _isfl *)buf;
|
||||
|
||||
/* Allocate a memory buffer */
|
||||
//printk( KERN_INFO "Allocate Memory size: %ld\n", isfl->mbuf_size );
|
||||
|
||||
isfl_mem_buff = kmalloc( isfl->mbuf_size, GFP_DMA ); //20090605 - Keep OS allocate under 16M
|
||||
if ( isfl_mem_buff == NULL )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memset( isfl_mem_buff, 0, isfl->mbuf_size );
|
||||
|
||||
isfl_phys_addr = virt_to_phys( isfl_mem_buff );
|
||||
//printk( KERN_INFO "isfl: virt: 0x%p phys: 0x%08lx\n", isfl_mem_buff, isfl_phys_addr );
|
||||
isfl->mbuf_paddr = isfl_phys_addr;
|
||||
//printk( KERN_INFO "Memory physical addr: 0x%08lx\n", isfl->mbuf_paddr );
|
||||
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
//printk( KERN_INFO "%02X ", buf[i] );
|
||||
put_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
//printk( KERN_INFO "\n" );
|
||||
break;
|
||||
|
||||
case IOCTL_FREE_MEMORY:
|
||||
//printk( KERN_INFO "IOCTL_FREE_MEMORY\n" );
|
||||
//kfree( isfl_mem_buff );
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
//printk( KERN_INFO "%02X ", buf[i] );
|
||||
}
|
||||
|
||||
isfl = (struct _isfl *)buf;
|
||||
isfl_phys_addr = isfl->mbuf_paddr;
|
||||
|
||||
vir_addr = (unsigned char*)phys_to_virt (isfl_phys_addr);
|
||||
if ( vir_addr == NULL )
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_READ_FROME_PHYSICAL with failure from phys_to_virt\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
kfree (vir_addr);
|
||||
break;
|
||||
|
||||
case IOCTL_GENERATE_SMI:
|
||||
//printk( "IOCTL_GENERATE_SMI\n" );
|
||||
|
||||
//printk( "size of (struct _isfl): %d\n", isfl_size );
|
||||
|
||||
/* Get SMI initial data */
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
//printk( "%02X ", buf[i] );
|
||||
}
|
||||
//printk( "\n" );
|
||||
isfl = (struct _isfl *)buf;
|
||||
//printk( "SMI IO port: 0x%lX\n", isfl->smi_io );
|
||||
//printk( "Bufer Size: %ld\n", isfl->mbuf_size );
|
||||
break;
|
||||
|
||||
case IOCTL_GET_SMI_STATUS:
|
||||
//printk( "IOCTL_GET_SMI_STATUS\n" );
|
||||
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
//printk( "%02X ", buf[i] );
|
||||
put_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
//printk( "\n" );
|
||||
break;
|
||||
|
||||
case IOCTL_ENABLE_KBC:
|
||||
enable_a20_kbc();
|
||||
break;
|
||||
|
||||
case IOCTL_DISABLE_KBC:
|
||||
disable_a20_kbc();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
static DEFINE_MUTEX( isflash_mutex );
|
||||
static long isfl_ioctl_unlock(struct file *fp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
long ret;
|
||||
mutex_lock( &isflash_mutex );
|
||||
ret = isfl_ioctl( fp, cmd, arg );
|
||||
mutex_unlock( &isflash_mutex );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct file_operations fops = {
|
||||
.read = isfl_read,
|
||||
.write = isfl_write,
|
||||
.open = isfl_open,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
.unlocked_ioctl = isfl_ioctl_unlock,
|
||||
.compat_ioctl = isfl_ioctl_unlock,
|
||||
#else
|
||||
.ioctl = isfl_ioctl,
|
||||
#endif
|
||||
.release = isfl_release
|
||||
};
|
||||
|
||||
//Driver initialization
|
||||
static int __init init_isfl(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
first = MKDEV(DEVICE_MAJOR_NUM, 0);
|
||||
if (register_chrdev_region(first, 1, DEVICE_NAME) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if ((isfl_class = class_create(THIS_MODULE, DEVICE_NAME)) == NULL)
|
||||
{
|
||||
unregister_chrdev_region(first, 1);
|
||||
return -1;
|
||||
}
|
||||
if (device_create(isfl_class, NULL, first, NULL, "isfl") == NULL)
|
||||
{
|
||||
class_destroy(isfl_class);
|
||||
unregister_chrdev_region(first, 1);
|
||||
return -1;
|
||||
}
|
||||
cdev_init(&c_dev, &fops);
|
||||
if (cdev_add(&c_dev, first, 1) == -1)
|
||||
{
|
||||
device_destroy(isfl_class, first);
|
||||
class_destroy(isfl_class);
|
||||
unregister_chrdev_region(first, 1);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
int ret = register_chrdev(DEVICE_MAJOR_NUM, DEVICE_NAME, &fops);
|
||||
if ( ret < 0 )
|
||||
{
|
||||
//printk( KERN_ALERT "Registering char device %s failed with %d\n", DEVICE_NAME, ret );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
//printk ("<0> IOCTL_ALLOCATE_MEMORY = %lx\n", IOCTL_ALLOCATE_MEMORY );
|
||||
//printk ("<0> IOCTL_FREE_MEMORY = %lx\n", IOCTL_FREE_MEMORY );
|
||||
//printk ("<0> IOCTL_WRITE_MEMORY = %lx\n", IOCTL_WRITE_MEMORY );
|
||||
//printk ("<0> IOCTL_READ_MEMORY = %lx\n", IOCTL_READ_MEMORY );
|
||||
//printk ("<0> IOCTL_GENERATE_SMI = %lx\n", IOCTL_GENERATE_SMI );
|
||||
//printk ("<0> IOCTL_GET_SMI_STATUS = %lx\n", IOCTL_GET_SMI_STATUS );
|
||||
//printk ("<0> IOCTL_DISABLE_KBC = %lx\n", IOCTL_DISABLE_KBC );
|
||||
//printk ("<0> IOCTL_ENABLE_KBC = %lx\n", IOCTL_ENABLE_KBC );
|
||||
//printk ("<0> IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY = %lx\n", IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY);
|
||||
//printk ("<0> IOCTL_FREE_MULTI_BLOCK_MEMORY = %lx\n", IOCTL_FREE_MULTI_BLOCK_MEMORY );
|
||||
//printk ("<0> IOCTL_COPY_BUFFER_TO_MEMORY = %lx\n", IOCTL_COPY_BUFFER_TO_MEMORY );
|
||||
//printk ("<0> = %d\n", MAJOR(first));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_isfl(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
cdev_del(&c_dev);
|
||||
device_destroy(isfl_class, first);
|
||||
class_destroy(isfl_class);
|
||||
unregister_chrdev_region(first, 1);
|
||||
#else
|
||||
unregister_chrdev( DEVICE_MAJOR_NUM, DEVICE_NAME );
|
||||
#endif
|
||||
}
|
||||
|
||||
static int isfl_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if ( Device_Open )
|
||||
{
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
Device_Open++;
|
||||
try_module_get( THIS_MODULE );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isfl_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
Device_Open--;
|
||||
|
||||
module_put( THIS_MODULE );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t isfl_read(struct file *filp, char *buff, size_t len, loff_t *offset)
|
||||
{
|
||||
int bytes_read = 0;
|
||||
|
||||
//printk( KERN_INFO "isfl_read\n" );
|
||||
|
||||
if ( isfl_mem_buff == 0 )
|
||||
{
|
||||
//printk( KERN_ERR "Memory buffer in kernel space that maybe not be allocated!\n" );
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
while ( len )
|
||||
{
|
||||
put_user( isfl_mem_buff[bytes_read++], buff++ );
|
||||
len--;
|
||||
}
|
||||
|
||||
//printk( KERN_INFO "isfl_read: read %d bytes, left %d\n", bytes_read, len );
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static ssize_t isfl_write(struct file *file, const char *buff, size_t len, loff_t *offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
//printk( KERN_INFO "isfl_write\n" );
|
||||
|
||||
if ( isfl_mem_buff == 0 )
|
||||
{
|
||||
//printk( KERN_ERR "Memory buffer in kernel space that maybe not be allocated!\n" );
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
//printk( KERN_INFO "isfl_write: len: %d\n", len );
|
||||
|
||||
for ( i = 0; i < len && i < ISFB_FLASH_SIZE; i++ )
|
||||
{
|
||||
get_user( *( isfl_mem_buff + i ), buff + i );
|
||||
}
|
||||
#if 0
|
||||
for ( i = 0; i < len; i++ )
|
||||
{
|
||||
if ( ( i + 1 ) % 8 )
|
||||
{
|
||||
//printk( "%02x ", isfl_mem_buff[i] );
|
||||
}
|
||||
else if ( ( i + 1 ) %16 )
|
||||
{
|
||||
//printk( "%02x ", isfl_mem_buff[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
//printk( "%02x\n", isfl_mem_buff[i] );
|
||||
}
|
||||
}
|
||||
//printk( "\n" );
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
|
||||
static int empty_8042(void)
|
||||
{
|
||||
u8 status;
|
||||
int loops = MAX_8042_LOOPS;
|
||||
|
||||
while ( loops-- )
|
||||
{
|
||||
io_delay();
|
||||
|
||||
status = inb( 0x64 );
|
||||
if ( status & 1 )
|
||||
{
|
||||
/* Read and discard input data */
|
||||
io_delay();
|
||||
(void)inb( 0x60 );
|
||||
}
|
||||
else if ( !( status & 2 ) )
|
||||
{
|
||||
/* Buffers empty, finished! */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void enable_a20_kbc(void)
|
||||
{
|
||||
empty_8042();
|
||||
|
||||
outb( 0x60, 0x64 ); // Command write
|
||||
empty_8042();
|
||||
|
||||
outb( 0x47, 0x60 ); // A20 on
|
||||
empty_8042();
|
||||
}
|
||||
|
||||
static void disable_a20_kbc(void)
|
||||
{
|
||||
empty_8042();
|
||||
|
||||
outb( 0x60, 0x64 ); // Command write
|
||||
empty_8042();
|
||||
|
||||
outb( 0x74, 0x60 ); // A20 on
|
||||
empty_8042();
|
||||
}
|
||||
|
||||
static inline void io_delay(void)
|
||||
{
|
||||
const u16 DELAY_PORT = 0x80;
|
||||
asm volatile( "outb %%al,%0" : : "dN" (DELAY_PORT) );
|
||||
}
|
||||
|
||||
module_init( init_isfl );
|
||||
module_exit( cleanup_isfl );
|
||||
|
||||
MODULE_AUTHOR( DRIVER_AUTHOR );
|
||||
MODULE_DESCRIPTION( DRIVER_DESC );
|
||||
MODULE_VERSION( ISFL_VERSION );
|
||||
MODULE_SUPPORTED_DEVICE( "Insyde EFI BIOS Flash" );
|
||||
MODULE_LICENSE( "GPL" );
|
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# Makefile for InsydeFlash tool for Linux (build your main kernel)
|
||||
#
|
||||
MACHINE = $(shell uname -m)
|
||||
|
||||
obj-m+=isfl_drv.o
|
||||
|
||||
|
||||
all: isfl_drv
|
||||
|
||||
isfl_drv:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* InsydeFlash Linux Driver
|
||||
* File: isfl.h
|
||||
*
|
||||
* Copyright (C) 2005 - 2015 Insyde Software Corp.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#define DEVICE_NAME "isfl" //InsydeFlash buffer
|
||||
#define DEVICE_NAME_PATH "/dev/"DEVICE_NAME // Open device node on user-space
|
||||
#define DEVICE_MAJOR_NUM 100
|
||||
#define ISFB_FLASH_SIZE ( 128 * 1024 ) // 128KB
|
||||
#define MEMORY_BLOCK_SIZE ( 64 * 1024 ) // 64KB
|
||||
#define MAX_MEMORY_BLOCK_COUNT 512
|
||||
|
||||
struct _isfl
|
||||
{
|
||||
unsigned long smi_io; // SMI Port
|
||||
unsigned long mbuf_size; // memory buffer size
|
||||
unsigned long mbuf_paddr; // memory buffer physical address
|
||||
unsigned long smi_status; // SW SMI Status Return
|
||||
unsigned long enable_kbc;
|
||||
unsigned long disable_kbc;
|
||||
};
|
||||
|
||||
struct _mblock
|
||||
{
|
||||
unsigned long mbuf_PhyAddr; // memory buffer index
|
||||
unsigned long mbuf_size; // memory buffer size
|
||||
unsigned char pbyBuffer[MEMORY_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
#define IOCTL_ALLOCATE_MEMORY _IOWR(DEVICE_MAJOR_NUM, 0, struct _isfl *)
|
||||
#define IOCTL_FREE_MEMORY _IOW(DEVICE_MAJOR_NUM, 1, struct _isfl *)
|
||||
#define IOCTL_WRITE_MEMORY _IOWR(DEVICE_MAJOR_NUM, 2, struct _isfl *)
|
||||
#define IOCTL_READ_MEMORY _IOWR(DEVICE_MAJOR_NUM, 3, struct _isfl *)
|
||||
#define IOCTL_GENERATE_SMI _IOW(DEVICE_MAJOR_NUM, 4, struct _isfl *)
|
||||
#define IOCTL_GET_SMI_STATUS _IOR(DEVICE_MAJOR_NUM, 5, struct _isfl *)
|
||||
#define IOCTL_DISABLE_KBC _IOR(DEVICE_MAJOR_NUM, 6, struct _isfl *)
|
||||
#define IOCTL_ENABLE_KBC _IOR(DEVICE_MAJOR_NUM, 7, struct _isfl *)
|
||||
#define IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY _IOWR(DEVICE_MAJOR_NUM, 8, struct _isfl *)
|
||||
#define IOCTL_FREE_MULTI_BLOCK_MEMORY _IOW(DEVICE_MAJOR_NUM, 9, struct _isfl *)
|
||||
#define IOCTL_WRITE_TO_PHYSICAL _IOWR(DEVICE_MAJOR_NUM, 10, struct _mblock *)
|
||||
#define IOCTL_READ_FROME_PHYSICAL _IOWR(DEVICE_MAJOR_NUM, 11, struct _mblock *)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,558 @@
|
|||
/*
|
||||
* InsydeFlash Linux Driver
|
||||
* File: isfl_drv.c
|
||||
*
|
||||
* Copyright (C) 2005 - 2015 Insyde Software Corp.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/version.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
typedef struct _PageAlloc {
|
||||
unsigned long addr;
|
||||
unsigned long PhyAddr;
|
||||
unsigned int order;
|
||||
}PageAlloc_t;
|
||||
|
||||
#include "isfl.h"
|
||||
|
||||
#define MAX_8042_LOOPS 100000
|
||||
|
||||
#define ISFL_VERSION "0.0.05"
|
||||
#define DRIVER_AUTHOR "Howard Ho <howard.ho@insydesw.com.tw>"
|
||||
#define DRIVER_DESC "InsydeFlash tool for Linux"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
static dev_t first;
|
||||
static struct cdev c_dev;
|
||||
static struct class *isfl_class;
|
||||
#endif
|
||||
|
||||
static int Device_Open = 0;
|
||||
static unsigned char *isfl_mem_buff;
|
||||
static unsigned char *g_ppbyMemoryBuffer[MAX_MEMORY_BLOCK_COUNT] = {0};
|
||||
static PageAlloc_t g_ppbyMemoryBuffer2[MAX_MEMORY_BLOCK_COUNT] = {{0,0}};
|
||||
static int isfl_open(struct inode *, struct file *);
|
||||
static int isfl_release(struct inode *, struct file *);
|
||||
static ssize_t isfl_read(struct file *, char *, size_t, loff_t *);
|
||||
static ssize_t isfl_write(struct file *file, const char *buff, size_t length, loff_t *offset);
|
||||
//Flash will close kbc except show dialog
|
||||
static void enable_a20_kbc(void);
|
||||
static void disable_a20_kbc(void);
|
||||
//static int empty_8042(void);
|
||||
static inline void io_delay(void);
|
||||
|
||||
//Use this function to get the message from AP
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
static long isfl_ioctl(struct file *file, unsigned int num, unsigned long arg)
|
||||
#else
|
||||
static int isfl_ioctl(struct inode *inode, struct file *file, unsigned int num, unsigned long arg)
|
||||
#endif
|
||||
{
|
||||
unsigned long isfl_phys_addr; // Assgin to SW SMI
|
||||
struct _isfl *isfl;
|
||||
int isfl_size = sizeof( struct _isfl );
|
||||
unsigned char buf[isfl_size];
|
||||
struct _mblock *pBlock;
|
||||
int iBlockStructureSize = sizeof( struct _mblock );
|
||||
unsigned char *pbyBlockBuffer;
|
||||
unsigned char *ch;
|
||||
int i;
|
||||
unsigned long mbuf_index;
|
||||
unsigned char *vir_addr = 0;
|
||||
|
||||
switch ( num )
|
||||
{
|
||||
case IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY:
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
isfl = (struct _isfl *)buf;
|
||||
|
||||
mbuf_index = isfl->mbuf_paddr; // use mbuf_paddr to store mbuf_index to backward compatible
|
||||
|
||||
// Allocate memory buffer
|
||||
g_ppbyMemoryBuffer2[mbuf_index].order = get_order( isfl->mbuf_size );
|
||||
g_ppbyMemoryBuffer2[mbuf_index].addr = __get_free_pages( GFP_DMA32, g_ppbyMemoryBuffer2[mbuf_index].order );
|
||||
g_ppbyMemoryBuffer[mbuf_index] = (unsigned char *)g_ppbyMemoryBuffer2[mbuf_index].addr;
|
||||
if ( g_ppbyMemoryBuffer[mbuf_index] == NULL )
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY allocate physical memory failed\n" );
|
||||
return -1;
|
||||
}
|
||||
memset( g_ppbyMemoryBuffer[mbuf_index], 0, isfl->mbuf_size );
|
||||
|
||||
g_ppbyMemoryBuffer2[mbuf_index].PhyAddr = virt_to_phys( g_ppbyMemoryBuffer[mbuf_index] );
|
||||
isfl->mbuf_paddr = g_ppbyMemoryBuffer2[mbuf_index].PhyAddr;
|
||||
//printk( KERN_INFO "isfl alloc id=%d, PhyAddr=%x\n", mbuf_index, g_ppbyMemoryBuffer2[mbuf_index].PhyAddr );
|
||||
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
put_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case IOCTL_FREE_MULTI_BLOCK_MEMORY:
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
isfl = (struct _isfl *)buf;
|
||||
|
||||
mbuf_index = -1;
|
||||
isfl_phys_addr = isfl->mbuf_paddr;
|
||||
for (i = 0; i < MAX_MEMORY_BLOCK_COUNT; i++)
|
||||
if (isfl_phys_addr == g_ppbyMemoryBuffer2[i].PhyAddr)
|
||||
mbuf_index = i;
|
||||
if (-1 == mbuf_index)
|
||||
return -1;
|
||||
|
||||
// Free Memory
|
||||
if ( g_ppbyMemoryBuffer[mbuf_index] != NULL )
|
||||
{
|
||||
free_pages( g_ppbyMemoryBuffer2[mbuf_index].addr, g_ppbyMemoryBuffer2[mbuf_index].order );
|
||||
g_ppbyMemoryBuffer2[mbuf_index].addr = 0;
|
||||
g_ppbyMemoryBuffer2[mbuf_index].order = 0;
|
||||
g_ppbyMemoryBuffer[mbuf_index] = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case IOCTL_WRITE_TO_PHYSICAL:
|
||||
ch = (unsigned char *)arg;
|
||||
pbyBlockBuffer = kmalloc( iBlockStructureSize, GFP_DMA );
|
||||
if ( pbyBlockBuffer == NULL )
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_WRITE_TO_PHYSICAL with NULL parameter\n" );
|
||||
return -1;
|
||||
}
|
||||
for ( i = 0; i < iBlockStructureSize; i++ )
|
||||
{
|
||||
get_user( pbyBlockBuffer[i], ( ch + i ) );
|
||||
}
|
||||
pBlock = (struct _mblock *)pbyBlockBuffer;
|
||||
isfl_phys_addr = pBlock->mbuf_PhyAddr;
|
||||
//printk( KERN_INFO "isfl write PhyAddr=%x\n", pBlock->mbuf_PhyAddr);
|
||||
//printk( KERN_INFO "isfl write len=%x\n", pBlock->mbuf_size);
|
||||
//printk( KERN_INFO "isfl write PhyAddr=%x\n", isfl_phys_addr );
|
||||
|
||||
mbuf_index = -1;
|
||||
for (i = 0; i < MAX_MEMORY_BLOCK_COUNT; i++)
|
||||
if (isfl_phys_addr == g_ppbyMemoryBuffer2[i].PhyAddr)
|
||||
mbuf_index = i;
|
||||
if (-1 == mbuf_index)
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_WRITE_TO_PHYSICAL with wrong physcial address\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( g_ppbyMemoryBuffer[mbuf_index] == NULL )
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_WRITE_TO_PHYSICAL with physcial address didn't allocate\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( i = 0; i < pBlock->mbuf_size && i < ISFB_FLASH_SIZE; i++ )
|
||||
{
|
||||
g_ppbyMemoryBuffer[mbuf_index][i] = pBlock->pbyBuffer[i];
|
||||
}
|
||||
|
||||
kfree( pbyBlockBuffer );
|
||||
break;
|
||||
|
||||
case IOCTL_READ_FROME_PHYSICAL:
|
||||
ch = (unsigned char *)arg;
|
||||
pbyBlockBuffer = kmalloc( iBlockStructureSize, GFP_DMA );
|
||||
if ( pbyBlockBuffer == NULL )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for ( i = 0; i < iBlockStructureSize; i++ )
|
||||
{
|
||||
get_user( pbyBlockBuffer[i], ( ch + i ) );
|
||||
}
|
||||
pBlock = (struct _mblock *)pbyBlockBuffer;
|
||||
isfl_phys_addr = pBlock->mbuf_PhyAddr;
|
||||
//printk( KERN_INFO "isfl read PhyAddr=%x\n", pBlock->mbuf_PhyAddr);
|
||||
//printk( KERN_INFO "isfl read len=%x\n", pBlock->mbuf_size);
|
||||
//printk( KERN_INFO "isfl read PhyAddr=%x\n", isfl_phys_addr );
|
||||
|
||||
mbuf_index = -1;
|
||||
for (i = 0; i < MAX_MEMORY_BLOCK_COUNT; i++)
|
||||
if (isfl_phys_addr == g_ppbyMemoryBuffer2[i].PhyAddr)
|
||||
mbuf_index = i;
|
||||
if (-1 == mbuf_index)
|
||||
return -1;
|
||||
|
||||
if ( g_ppbyMemoryBuffer[mbuf_index] == NULL )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( i = 0; i < pBlock->mbuf_size && i < ISFB_FLASH_SIZE; i++ )
|
||||
{
|
||||
pBlock->pbyBuffer[i] = g_ppbyMemoryBuffer[mbuf_index][i];
|
||||
}
|
||||
|
||||
for ( i = 0; i < iBlockStructureSize; i++ )
|
||||
{
|
||||
put_user( pbyBlockBuffer[i], ( ch + i ) );
|
||||
}
|
||||
kfree( pbyBlockBuffer );
|
||||
break;
|
||||
|
||||
case IOCTL_ALLOCATE_MEMORY:
|
||||
//printk( KERN_INFO "IOCTL_ALLOCATE_MEMORY\n" );
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
//printk( KERN_INFO "%02X ", buf[i] );
|
||||
}
|
||||
//printk( KERN_INFO "\n" );
|
||||
isfl = (struct _isfl *)buf;
|
||||
|
||||
/* Allocate a memory buffer */
|
||||
//printk( KERN_INFO "Allocate Memory size: %ld\n", isfl->mbuf_size );
|
||||
|
||||
isfl_mem_buff = kmalloc( isfl->mbuf_size, GFP_DMA ); //20090605 - Keep OS allocate under 16M
|
||||
if ( isfl_mem_buff == NULL )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memset( isfl_mem_buff, 0, isfl->mbuf_size );
|
||||
|
||||
isfl_phys_addr = virt_to_phys( isfl_mem_buff );
|
||||
//printk( KERN_INFO "isfl: virt: 0x%p phys: 0x%08lx\n", isfl_mem_buff, isfl_phys_addr );
|
||||
isfl->mbuf_paddr = isfl_phys_addr;
|
||||
//printk( KERN_INFO "Memory physical addr: 0x%08lx\n", isfl->mbuf_paddr );
|
||||
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
//printk( KERN_INFO "%02X ", buf[i] );
|
||||
put_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
//printk( KERN_INFO "\n" );
|
||||
break;
|
||||
|
||||
case IOCTL_FREE_MEMORY:
|
||||
//printk( KERN_INFO "IOCTL_FREE_MEMORY\n" );
|
||||
//kfree( isfl_mem_buff );
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
//printk( KERN_INFO "%02X ", buf[i] );
|
||||
}
|
||||
|
||||
isfl = (struct _isfl *)buf;
|
||||
isfl_phys_addr = isfl->mbuf_paddr;
|
||||
|
||||
vir_addr = (unsigned char*)phys_to_virt (isfl_phys_addr);
|
||||
if ( vir_addr == NULL )
|
||||
{
|
||||
//printk( KERN_INFO "isfl ioctl IOCTL_READ_FROME_PHYSICAL with failure from phys_to_virt\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
kfree (vir_addr);
|
||||
break;
|
||||
|
||||
case IOCTL_GENERATE_SMI:
|
||||
//printk( "IOCTL_GENERATE_SMI\n" );
|
||||
|
||||
//printk( "size of (struct _isfl): %d\n", isfl_size );
|
||||
|
||||
/* Get SMI initial data */
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
get_user( buf[i], ( ch + i ) );
|
||||
//printk( "%02X ", buf[i] );
|
||||
}
|
||||
//printk( "\n" );
|
||||
isfl = (struct _isfl *)buf;
|
||||
//printk( "SMI IO port: 0x%lX\n", isfl->smi_io );
|
||||
//printk( "Bufer Size: %ld\n", isfl->mbuf_size );
|
||||
break;
|
||||
|
||||
case IOCTL_GET_SMI_STATUS:
|
||||
//printk( "IOCTL_GET_SMI_STATUS\n" );
|
||||
|
||||
ch = (unsigned char *)arg;
|
||||
for ( i = 0; i < isfl_size; i++ )
|
||||
{
|
||||
//printk( "%02X ", buf[i] );
|
||||
put_user( buf[i], ( ch + i ) );
|
||||
}
|
||||
//printk( "\n" );
|
||||
break;
|
||||
|
||||
case IOCTL_ENABLE_KBC:
|
||||
enable_a20_kbc();
|
||||
break;
|
||||
|
||||
case IOCTL_DISABLE_KBC:
|
||||
disable_a20_kbc();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
static DEFINE_MUTEX( isflash_mutex );
|
||||
static long isfl_ioctl_unlock(struct file *fp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
long ret;
|
||||
mutex_lock( &isflash_mutex );
|
||||
ret = isfl_ioctl( fp, cmd, arg );
|
||||
mutex_unlock( &isflash_mutex );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct file_operations fops = {
|
||||
.read = isfl_read,
|
||||
.write = isfl_write,
|
||||
.open = isfl_open,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
.unlocked_ioctl = isfl_ioctl_unlock,
|
||||
.compat_ioctl = isfl_ioctl_unlock,
|
||||
#else
|
||||
.ioctl = isfl_ioctl,
|
||||
#endif
|
||||
.release = isfl_release
|
||||
};
|
||||
|
||||
//Driver initialization
|
||||
static int __init init_isfl(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
first = MKDEV(DEVICE_MAJOR_NUM, 0);
|
||||
if (register_chrdev_region(first, 1, DEVICE_NAME) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if ((isfl_class = class_create(THIS_MODULE, DEVICE_NAME)) == NULL)
|
||||
{
|
||||
unregister_chrdev_region(first, 1);
|
||||
return -1;
|
||||
}
|
||||
if (device_create(isfl_class, NULL, first, NULL, "isfl") == NULL)
|
||||
{
|
||||
class_destroy(isfl_class);
|
||||
unregister_chrdev_region(first, 1);
|
||||
return -1;
|
||||
}
|
||||
cdev_init(&c_dev, &fops);
|
||||
if (cdev_add(&c_dev, first, 1) == -1)
|
||||
{
|
||||
device_destroy(isfl_class, first);
|
||||
class_destroy(isfl_class);
|
||||
unregister_chrdev_region(first, 1);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
int ret = register_chrdev(DEVICE_MAJOR_NUM, DEVICE_NAME, &fops);
|
||||
if ( ret < 0 )
|
||||
{
|
||||
//printk( KERN_ALERT "Registering char device %s failed with %d\n", DEVICE_NAME, ret );
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
//printk ("<0> IOCTL_ALLOCATE_MEMORY = %lx\n", IOCTL_ALLOCATE_MEMORY );
|
||||
//printk ("<0> IOCTL_FREE_MEMORY = %lx\n", IOCTL_FREE_MEMORY );
|
||||
//printk ("<0> IOCTL_WRITE_MEMORY = %lx\n", IOCTL_WRITE_MEMORY );
|
||||
//printk ("<0> IOCTL_READ_MEMORY = %lx\n", IOCTL_READ_MEMORY );
|
||||
//printk ("<0> IOCTL_GENERATE_SMI = %lx\n", IOCTL_GENERATE_SMI );
|
||||
//printk ("<0> IOCTL_GET_SMI_STATUS = %lx\n", IOCTL_GET_SMI_STATUS );
|
||||
//printk ("<0> IOCTL_DISABLE_KBC = %lx\n", IOCTL_DISABLE_KBC );
|
||||
//printk ("<0> IOCTL_ENABLE_KBC = %lx\n", IOCTL_ENABLE_KBC );
|
||||
//printk ("<0> IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY = %lx\n", IOCTL_ALLOCATE_MULTI_BLOCK_MEMORY);
|
||||
//printk ("<0> IOCTL_FREE_MULTI_BLOCK_MEMORY = %lx\n", IOCTL_FREE_MULTI_BLOCK_MEMORY );
|
||||
//printk ("<0> IOCTL_COPY_BUFFER_TO_MEMORY = %lx\n", IOCTL_COPY_BUFFER_TO_MEMORY );
|
||||
//printk ("<0> = %d\n", MAJOR(first));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_isfl(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 36 )
|
||||
cdev_del(&c_dev);
|
||||
device_destroy(isfl_class, first);
|
||||
class_destroy(isfl_class);
|
||||
unregister_chrdev_region(first, 1);
|
||||
#else
|
||||
unregister_chrdev( DEVICE_MAJOR_NUM, DEVICE_NAME );
|
||||
#endif
|
||||
}
|
||||
|
||||
static int isfl_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if ( Device_Open )
|
||||
{
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
Device_Open++;
|
||||
try_module_get( THIS_MODULE );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isfl_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
Device_Open--;
|
||||
|
||||
module_put( THIS_MODULE );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t isfl_read(struct file *filp, char *buff, size_t len, loff_t *offset)
|
||||
{
|
||||
int bytes_read = 0;
|
||||
|
||||
//printk( KERN_INFO "isfl_read\n" );
|
||||
|
||||
if ( isfl_mem_buff == 0 )
|
||||
{
|
||||
//printk( KERN_ERR "Memory buffer in kernel space that maybe not be allocated!\n" );
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
while ( len )
|
||||
{
|
||||
put_user( isfl_mem_buff[bytes_read++], buff++ );
|
||||
len--;
|
||||
}
|
||||
|
||||
//printk( KERN_INFO "isfl_read: read %d bytes, left %d\n", bytes_read, len );
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static ssize_t isfl_write(struct file *file, const char *buff, size_t len, loff_t *offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
//printk( KERN_INFO "isfl_write\n" );
|
||||
|
||||
if ( isfl_mem_buff == 0 )
|
||||
{
|
||||
//printk( KERN_ERR "Memory buffer in kernel space that maybe not be allocated!\n" );
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
//printk( KERN_INFO "isfl_write: len: %d\n", len );
|
||||
|
||||
for ( i = 0; i < len && i < ISFB_FLASH_SIZE; i++ )
|
||||
{
|
||||
get_user( *( isfl_mem_buff + i ), buff + i );
|
||||
}
|
||||
#if 0
|
||||
for ( i = 0; i < len; i++ )
|
||||
{
|
||||
if ( ( i + 1 ) % 8 )
|
||||
{
|
||||
//printk( "%02x ", isfl_mem_buff[i] );
|
||||
}
|
||||
else if ( ( i + 1 ) %16 )
|
||||
{
|
||||
//printk( "%02x ", isfl_mem_buff[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
//printk( "%02x\n", isfl_mem_buff[i] );
|
||||
}
|
||||
}
|
||||
//printk( "\n" );
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
|
||||
static int empty_8042(void)
|
||||
{
|
||||
u8 status;
|
||||
int loops = MAX_8042_LOOPS;
|
||||
|
||||
while ( loops-- )
|
||||
{
|
||||
io_delay();
|
||||
|
||||
status = inb( 0x64 );
|
||||
if ( status & 1 )
|
||||
{
|
||||
/* Read and discard input data */
|
||||
io_delay();
|
||||
(void)inb( 0x60 );
|
||||
}
|
||||
else if ( !( status & 2 ) )
|
||||
{
|
||||
/* Buffers empty, finished! */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void enable_a20_kbc(void)
|
||||
{
|
||||
empty_8042();
|
||||
|
||||
outb( 0x60, 0x64 ); // Command write
|
||||
empty_8042();
|
||||
|
||||
outb( 0x47, 0x60 ); // A20 on
|
||||
empty_8042();
|
||||
}
|
||||
|
||||
static void disable_a20_kbc(void)
|
||||
{
|
||||
empty_8042();
|
||||
|
||||
outb( 0x60, 0x64 ); // Command write
|
||||
empty_8042();
|
||||
|
||||
outb( 0x74, 0x60 ); // A20 on
|
||||
empty_8042();
|
||||
}
|
||||
|
||||
static inline void io_delay(void)
|
||||
{
|
||||
const u16 DELAY_PORT = 0x80;
|
||||
asm volatile( "outb %%al,%0" : : "dN" (DELAY_PORT) );
|
||||
}
|
||||
|
||||
module_init( init_isfl );
|
||||
module_exit( cleanup_isfl );
|
||||
|
||||
MODULE_AUTHOR( DRIVER_AUTHOR );
|
||||
MODULE_DESCRIPTION( DRIVER_DESC );
|
||||
MODULE_VERSION( ISFL_VERSION );
|
||||
MODULE_SUPPORTED_DEVICE( "Insyde EFI BIOS Flash" );
|
||||
MODULE_LICENSE( "GPL" );
|
Loading…
Reference in New Issue