#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#define APPLE_MEM_CLEAR (0x1)
#define BUF "what a fucking day!"
char buf[100];
int main(int argc, char * argv[])
{
int fd;
fd = open("/dev/apple", O_RDWR);
if (!fd){
printf("/dev/apple open failure.\n");
}
lseek(fd, 0, 20);
write(fd, BUF, sizeof(BUF));
lseek(fd, 0, 0);
read(fd, buf, 100);
printf("read: %s\n", buf);
printf("----------clear---------\n");
ioctl(fd, APPLE_MEM_CLEAR);
lseek(fd, 0, 0);
read(fd, buf, 100);
printf("read: %s\n", buf);
close(fd);
return 0;
}
<pre name="code" class="cpp">MODULE_NAME := apple
obj-m :=$(MODULE_NAME).o
KERNEL_PATH ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNEL_PATH) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNEL_PATH) M=$(PWD) clean
<pre name="code" class="cpp">/*
* apple.c
*
* 2014/10/23 Steven King created
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#include <asm/device.h>
#define APPLE_DEV_NAME "apple"
#define APPLE_MEM_SIZE (16 * 1024)
#define APPLE_MEM_CLEAR (0x1)
static struct device * apple_dev;
static struct class * apple_cdev_class;
static dev_t apple_dev_t = 0;
static int apple_major_num = 0;
static int apple_minor_num = 0;
struct apple_struct{
struct cdev * apple_cdev;
unsigned char * apple_mem;
unsigned char * apple_p;
};
struct apple_struct * apple;
static int apple_open(struct inode *node, struct file *filp)
{
filp->private_data = apple;
apple->apple_p = apple->apple_mem;
return 0;
}
static ssize_t apple_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
int ret = 0;
unsigned char * tmp;
apple = filp->private_data;
tmp = apple->apple_p;
if (len > APPLE_MEM_SIZE){
printk("apple_read read overflow.\n");
ret = -EINVAL;
return ret;
}
if ((apple->apple_p + len) > (apple->apple_mem + APPLE_MEM_SIZE)){
len = apple->apple_mem + APPLE_MEM_SIZE - apple->apple_p;
}
if (copy_to_user(buf, apple->apple_p, len)){
printk("apple_read failure.\n");
ret = -EINVAL;
return ret;
}
apple->apple_p += len;
printk(KERN_INFO "read %d bytes(s) from 0x%p to 0x%p.\n", (int)len, tmp, apple->apple_p);
ret = len;
return ret;
}
static ssize_t apple_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
int ret = 0;
unsigned char * tmp;
apple = filp->private_data;
tmp = apple->apple_p;
if (len > APPLE_MEM_SIZE){
printk("apple_write write overflow.\n");
ret = -EINVAL;
return ret;
}
if ((apple->apple_p + len) > (apple->apple_mem + APPLE_MEM_SIZE)){
len = apple->apple_mem + APPLE_MEM_SIZE - apple->apple_p;
}
if (copy_from_user(apple->apple_p, buf, len)){
printk("apple_write failure.\n");
ret = -EINVAL;
return ret;
}
apple->apple_p += len;
printk(KERN_INFO "write %d bytes(s) from 0x%p to 0x%p.\n", (int)len, tmp, apple->apple_p);
ret = len;
return ret;
}
static loff_t apple_llseek(struct file *filp, loff_t off, int whence)
{
loff_t ret = 0;
unsigned char * tmp;
apple = filp->private_data;
tmp = apple->apple_p;
if (off > APPLE_MEM_SIZE){
printk("apple_llseek seek overflow.\n");
ret = -EINVAL;
}
switch(whence){
case 0:
if (off < 0){
ret = -EINVAL;
break;
}
if ((unsigned int)off > APPLE_MEM_SIZE){
ret = -EINVAL;
break;
}
filp->f_pos = off;
ret = filp->f_pos;
apple->apple_p = apple->apple_mem + off;
break;
case 1:
if ((apple->apple_p + (unsigned int)off) > (apple->apple_mem + APPLE_MEM_SIZE)){
ret = -EINVAL;
break;
}
if ((apple->apple_p - (unsigned int)off) < apple->apple_mem){
ret = -EINVAL;
break;
}
filp->f_pos = (apple->apple_p + (unsigned int)off - apple->apple_mem);
ret = filp->f_pos;
apple->apple_p = (unsigned char *)(apple->apple_p + off);
break;
default:
ret = -EINVAL;
break;
}
printk(KERN_INFO "lseek from 0x%p to 0x%p.\n", tmp, apple->apple_p);
return ret;
}
static long apple_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
apple = filp->private_data;
switch(cmd){
case APPLE_MEM_CLEAR:
memset(apple->apple_mem, 0, APPLE_MEM_SIZE);
printk(KERN_INFO "apple_mem has set to zero.\n");
apple->apple_p = apple->apple_mem;
break;
default:
ret = -EINVAL;
return ret;
break;
}
return ret;
}
static int apple_release(struct inode * inode,struct file * file)
{
int ret = 0;
return ret;
}
static const struct file_operations apple_fops =
{
.owner = THIS_MODULE,
.open = apple_open,
.read = apple_read,
.write = apple_write,
.llseek = apple_llseek,
.unlocked_ioctl = apple_ioctl,
.release = apple_release,
};
static int __init apple_init(void)
{
int ret = 0;
printk("Init apple: ");
ret = alloc_chrdev_region(&apple_dev_t, 0, 1, APPLE_DEV_NAME);
if (ret < 0){
printk("alloc_chrdev_region failure.\n");
goto Init_Err_Handle_alloc_chrdev_region;
}
apple_major_num = MAJOR(apple_dev_t);
apple_minor_num = MINOR(apple_dev_t);
apple_cdev_class = class_create(THIS_MODULE, APPLE_DEV_NAME);
if (IS_ERR(apple_cdev_class))
{
printk("Err: class_create failure.\n");
ret = 1;
goto Init_Err_Handle_class_create;
}
apple_dev = device_create(apple_cdev_class, NULL, apple_dev_t, NULL, APPLE_DEV_NAME);
//
apple = (struct apple_struct *)kmalloc(sizeof(struct apple_struct), GFP_KERNEL);
if (apple == NULL){
printk("Err: apple kmalloc failure.\n");
ret = 2;
goto Init_Err_Handle_apple;
}
apple->apple_cdev = cdev_alloc();
cdev_init(apple->apple_cdev, &apple_fops);
apple->apple_cdev->owner = THIS_MODULE;
cdev_add(apple->apple_cdev, apple_dev_t, 1);
//
apple->apple_mem = (unsigned char *)kmalloc(APPLE_MEM_SIZE * sizeof(char), GFP_KERNEL);
if (apple->apple_mem == NULL){
printk("Err: apple_mem kmalloc failure.\n");
ret = 3;
goto Init_Err_Handle_apple_mem;
}
memset(apple->apple_mem, 0, APPLE_MEM_SIZE * sizeof(char));
apple->apple_p = apple->apple_mem;
printk("Done.\n");
printk("major = %d, minor = %d\n", apple_major_num, apple_minor_num);
printk("apple_mem addr: 0x%p\n", apple->apple_mem);
return ret;
Init_Err_Handle_apple_mem:
kfree(apple->apple_mem);
cdev_del(apple->apple_cdev);
Init_Err_Handle_apple:
kfree(apple);
device_destroy(apple_cdev_class, apple_dev_t);
Init_Err_Handle_class_create:
class_destroy(apple_cdev_class);
Init_Err_Handle_alloc_chrdev_region:
unregister_chrdev_region(apple_dev_t, 1);
return ret;
}
static void __exit apple_exit(void)
{
printk("Exit apple: ");
kfree(apple->apple_mem);
cdev_del(apple->apple_cdev);
kfree(apple);
device_destroy(apple_cdev_class, apple_dev_t);
class_destroy(apple_cdev_class);
unregister_chrdev_region(apple_dev_t, 1);
printk("Done.\n");
}
module_init(apple_init);
module_exit(apple_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Steven King <sjin.stevenking55@gmail.com>");