rlyeh
Certified Guru
Can anyone compile this kernel module using GPH's toolchain 2.95 for linux?
I know I could install cygwin, then gcc, then arm-linux toolchain, then configure it and get this source finally compiled... but I'm lazy you know.
Btw, since it has never been compiled before it's probably full of bugs & syntax errors Sorry for that.
I know I could install cygwin, then gcc, then arm-linux toolchain, then configure it and get this source finally compiled... but I'm lazy you know.
Btw, since it has never been compiled before it's probably full of bugs & syntax errors Sorry for that.
Code:
/* Kernel device driver for Minimal Library SDK.
Based on previous work by Squidge and NK.
Written by rlyeh, (c) 2006. */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/memory.h>
#if __GNUC__ == 3
#include <linux/version.h>
static const char __module_kernel_version_gcc3[] __attribute__((__used__)) __attribute__((section(".modinfo"))) =
"kernel_version=" UTS_RELEASE;
#endif
#define MINIMAL_I2C_WRITE 0
#define MINIMAL_I2C_READ 1
#define MINIMAL_MMU_INSTALLHACK 2
#define MINIMAL_MMU_FLUSHCACHE 3
#define MINIMAL_MMU_R001 0x100
#define MINIMAL_MMU_R100 0x101
#define MINIMAL_MMU_W100 0x102
#define MINIMAL_MMU_R200 0x103
#define MINIMAL_MMU_W200 0x104
#define MINIMAL_MMU_R300 0x105
#define MINIMAL_MMU_W300 0x106
#define MINIMAL_MMU_R500 0x107
#define MINIMAL_MMU_W500 0x108
#define MINIMAL_MMU_R501 0x109
#define MINIMAL_MMU_W501 0x10a
#define MINIMAL_MMU_R600 0x10b
#define MINIMAL_MMU_W600 0x10c
#define MINIMAL_MMU_W750 0x10d
#define MINIMAL_MMU_W760 0x10e
#define MINIMAL_MMU_W770 0x10f
#define MINIMAL_MMU_W751 0x110
#define MINIMAL_MMU_W7131 0x111
#define MINIMAL_MMU_W761 0x112
#define MINIMAL_MMU_W7101 0x113
#define MINIMAL_MMU_W7141 0x114
#define MINIMAL_MMU_W7102 0x115
#define MINIMAL_MMU_W7104 0x116
#define MINIMAL_MMU_W7142 0x117
#define MINIMAL_MMU_W704 0x118
#define MINIMAL_MMU_W870 0x119
#define MINIMAL_MMU_W850 0x11a
#define MINIMAL_MMU_W851 0x11b
#define MINIMAL_MMU_W860 0x11c
#define MINIMAL_MMU_W861 0x11d
#define MINIMAL_MMU_R900 0x11e
#define MINIMAL_MMU_W900 0x11f
#define MINIMAL_MMU_R901 0x120
#define MINIMAL_MMU_W901 0x121
#define MINIMAL_MMU_R1000 0x122
#define MINIMAL_MMU_W1000 0x123
#define MINIMAL_MMU_R1001 0x124
#define MINIMAL_MMU_W1001 0x125
#define MINIMAL_MMU_R1300 0x126
#define MINIMAL_MMU_W1300 0x127
#define MINIMAL_MMU_DRAINWRITEBUFFER MINIMAL_MMU_W7104
#define MINIMAL_MMU_INVALIDATEICACHE MINIMAL_MMU_W750
#define MINIMAL_MMU_INVALIDATEDCACHE MINIMAL_MMU_W760
#define MMU_WRITE(act,ag) \
{ arg = ag; asm volatile( \
"stmdb sp!, {r0}\n\t" \
"mov r0, %0\n\t" \
"mcr p15, 0, r0, " act "\n\t" \
"ldmia sp!, {r0}\n\t": "=r" (arg)); }
#define MMU_READ(act,rt) \
{ asm volatile( \
"stmdb sp!, {r0}\n\t" \
"mrc p15, 0, r0, " act "\n\t" \
"mov %0, r0\n\t" \
"ldmia sp!, {r0}\n\t": "=r"(rt)); }
extern int I2C_wbyte( unsigned char id, unsigned char addr, unsigned char data );
extern int I2C_rbyte( unsigned char id, unsigned char addr, unsigned char *pData );
typedef struct { unsigned char id,addr,data;} i2cw;
typedef struct { unsigned char id,addr,*pdata;} i2cr;
static ssize_t minimal_open(struct inode *inode, struct file *filp)
{
return 0;
}
static int minimal_release(struct inode *inode, struct file *file)
{
return 0;
}
static int minimal_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long argm)
{
int ret, arg;
#define CMDR(c, a) if(cmd == (c)) { {a}; return (ret); }
#define CMDW(c, a) if(cmd == (c)) { copy_from_user(&arg, (int *)argm, sizeof(int)); {a}; return (1); }
//this group is here due to optimization reasons (faster execution)
CMDW(MINIMAL_MMU_W7104, MMU_WRITE("c7,c10,4",arg));
CMDW(MINIMAL_MMU_W750, MMU_WRITE("c7,c5,0", arg));
CMDW(MINIMAL_MMU_W760, MMU_WRITE("c7,c6,0", arg));
CMDW(MINIMAL_MMU_W770, MMU_WRITE("c7,c7,0", arg));
CMDW(MINIMAL_MMU_W751, MMU_WRITE("c7,c5,1", arg));
CMDW(MINIMAL_MMU_W7131, MMU_WRITE("c7,c13,1",arg));
CMDW(MINIMAL_MMU_W761, MMU_WRITE("c7,c6,1", arg));
CMDW(MINIMAL_MMU_W7101, MMU_WRITE("c7,c10,1",arg));
CMDW(MINIMAL_MMU_W7141, MMU_WRITE("c7,c14,1",arg));
CMDW(MINIMAL_MMU_W7102, MMU_WRITE("c7,c10,2",arg));
CMDW(MINIMAL_MMU_W7142, MMU_WRITE("c7,c14,2",arg));
CMDW(MINIMAL_MMU_W704, MMU_WRITE("c7,c0,4", arg));
CMDR(MINIMAL_MMU_R001, MMU_READ("c0,c0,1", ret));
CMDR(MINIMAL_MMU_R100, MMU_READ("c1,c0,0", ret));
CMDW(MINIMAL_MMU_W100, MMU_WRITE("c1,c0,0", arg));
CMDR(MINIMAL_MMU_R200, MMU_READ("c2,c0,0", ret));
CMDW(MINIMAL_MMU_W200, MMU_WRITE("c2,c0,0", arg));
CMDR(MINIMAL_MMU_R300, MMU_READ("c3,c0,0", ret));
CMDW(MINIMAL_MMU_W300, MMU_WRITE("c3,c0,0", arg));
CMDR(MINIMAL_MMU_R500, MMU_READ("c5,c0,0", ret));
CMDW(MINIMAL_MMU_W500, MMU_WRITE("c5,c0,0", arg));
CMDR(MINIMAL_MMU_R501, MMU_READ("c5,c0,1", ret));
CMDW(MINIMAL_MMU_W501, MMU_WRITE("c5,c0,1", arg));
CMDR(MINIMAL_MMU_R600, MMU_READ("c6,c0,0", ret));
CMDW(MINIMAL_MMU_W600, MMU_WRITE("c6,c0,0", arg));
CMDW(MINIMAL_MMU_W870, MMU_WRITE("c8,c7,0", arg));
CMDW(MINIMAL_MMU_W850, MMU_WRITE("c8,c5,0", arg));
CMDW(MINIMAL_MMU_W851, MMU_WRITE("c8,c5,1", arg));
CMDW(MINIMAL_MMU_W860, MMU_WRITE("c8,c6,0", arg));
CMDW(MINIMAL_MMU_W861, MMU_WRITE("c8,c6,1", arg));
CMDR(MINIMAL_MMU_R900, MMU_READ("c9,c0,0", ret));
CMDW(MINIMAL_MMU_W900, MMU_WRITE("c9,c0,0", arg));
CMDR(MINIMAL_MMU_R901, MMU_READ("c9,c0,1", ret));
CMDW(MINIMAL_MMU_W901, MMU_WRITE("c9,c0,1", arg));
CMDR(MINIMAL_MMU_R1000, MMU_READ("c10,c0,0", ret));
CMDW(MINIMAL_MMU_W1000, MMU_WRITE("c10,c0,0",arg));
CMDR(MINIMAL_MMU_R1001, MMU_READ("c10,c0,1", ret));
CMDW(MINIMAL_MMU_W1001, MMU_WRITE("c10,c0,1",arg));
CMDR(MINIMAL_MMU_R1300, MMU_READ("c13,c0,0", ret));
CMDW(MINIMAL_MMU_W1300, MMU_WRITE("c13,c0,0",arg));
if(cmd == MINIMAL_MMU_FLUSHCACHE)
{
asm volatile (".word 0xef9f0002"); // swi #0x9f0002
}
if(cmd == MINIMAL_I2C_WRITE)
{
i2cw i2c_write_info;
if(copy_from_user(&i2c_write_info, (i2cw *)argm, sizeof(i2cw)))
return -EFAULT;
mdelay(1);
I2C_wbyte(i2c_write_info.id, i2c_write_info.addr, i2c_write_info.data);
return 1;
}
if(cmd == MINIMAL_I2C_READ)
{
i2cr i2c_read_info;
if(copy_from_user(&i2c_read_info, (i2cr *)argm, sizeof(i2cr)))
return -EFAULT;
I2C_rbyte(i2c_read_info.id, i2c_read_info.addr, i2c_read_info.pdata);
return 1;
}
if(cmd == MINIMAL_MMU_INSTALLHACK)
{
unsigned int *pgtable, *cpt;
int i,j,ttb;
// get the pointer to the translation table base...
MMU_READ("c2,c0,0", ttb);
pgtable = __va(ttb);
for (i = 0; i < 4096; i ++) if ( (pgtable[i] & 3) == 1 ) {
cpt = __va(pgtable[i] & 0xfffffc00);
for (j = 0; j < 256; j ++)
if ( (cpt[j] & 0xff00000f) == 0x02000002 ||
(cpt[j] & 0xff00000f) == 0x03000002 ) {
// set C and B bits in upper 32MB memory area...
cpt[j] |= 0xFFC;
}
}
// drain the write buffer and flush the tlb caches...
MMU_WRITE("c7,c10,4",0)
MMU_WRITE("c8,c7,0",0);
return 1;
}
return -EINVAL;
}
static struct file_operations minimal_fops =
{
owner: THIS_MODULE,
ioctl: minimal_ioctl,
open: minimal_open,
release: minimal_release,
};
static struct miscdevice minimal =
{
255, "minimal", &minimal_fops
};
static int __init minimal_init(void)
{
misc_register(&minimal);
return 0;
}
static void __exit minimal_exit(void)
{
misc_deregister(&minimal);
}
module_init(minimal_init);
module_exit(minimal_exit);
MODULE_AUTHOR("rlyeh / www.retrodev.info");