mmap驱动
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/gfp.h>
#include <linux/uaccess.h>
#define PAGE_FAULT
#define PAGE_ORDER 0 //data_buff size: 4KB
#define MAX_SIZE (1UL << 12)
static struct page *page = NULL;
static char *hello_buf = NULL;
static struct class *hello_class;
static struct device *hello_device;
static struct cdev *hello_cdev;
static dev_t devno;
unsigned int pid;
module_param(pid, uint, 0644);
static int hello_open(struct inode *inode, struct file *file)
{
#ifndef PAGE_FAULT
page = alloc_pages(GFP_KERNEL, PAGE_ORDER);
if (!page) {
printk("alloc_pages fail!\n");
return -ENOMEM;
}
hello_buf = (char *)page_to_virt(page);
printk("data_buf phys_addr 0x%lx virt_addr 0x%lx\n",
page_to_phys(page), (unsigned long)hello_buf);
#endif
return 0;
}
static int hello_release(struct inode *inode, struct file *file)
{
__free_pages(page, PAGE_ORDER);
return 0;
}
static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
int len, ret;
char *token = NULL, *cur = hello_buf;
len = PAGE_SIZE - *ppos;
if (count > len)
count = len;
ret = copy_to_user(buf, hello_buf + *ppos, count);
if (ret)
return -EFAULT;
printk("read hello_buf %s\n", hello_buf);
token = strsep(&cur, " ");
while (token != NULL) {
printk("read %s\n", token);
token = strsep(&cur, " ");
}
*ppos += count;
return count;
}
static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
int len, ret;
char *token = NULL, *cur = hello_buf;
struct task_struct *task = NULL;
len = PAGE_SIZE - *ppos;
if (count > len)
count = len;
printk("hello write\n");
//simple_write_to_buffer()
ret = copy_from_user(hello_buf + *ppos, buf, count);
if (ret)
return -EFAULT;
printk("write hello_buf %s\n", hello_buf);
token = strsep(&cur, " ");
while (token != NULL) {
printk("write %s\n", token);
ret = kstrtouint(token, 10, &pid);
task = find_task_by_vpid(pid);
printk("pid %d task_name %s\n", (int)pid, task->comm);
token = strsep(&cur, " ");
}
printk("current task name %s\n", current->comm);
//printk("current_thread_info task name %s\n", current_thread_info()->task->comm);
printk("current_thread_info preempt_count %lx\n", current_thread_info()->preempt_count);
printk("current_thread_info count %ld\n", current_thread_info()->preempt.count);
printk("current_thread_info need_resched %ld\n", current_thread_info()->preempt.need_resched);
*ppos += count;
return count;
}
#ifdef PAGE_FAULT
struct vm_area_struct *vma;
vm_fault_t hello_fault(struct vm_fault *vmf)
{
printk("hello fault\n");
page = alloc_pages(GFP_KERNEL, PAGE_ORDER);
if (!page) {
printk("alloc pages fail\n");
return -ENOMEM;
}
hello_buf = (char *)page_to_virt(page);
printk("data_buf phys_addr 0x%lx virt_addr 0x%lx\n",
page_to_phys(page), (unsigned long)hello_buf);
vmf->page = page;
get_page(vmf->page);
return 0;
}
struct vm_operations_struct hello_vm_ops = {
.fault = hello_fault,
};
static int hello_mmap(struct file *file, struct vm_area_struct *vmap)
{
vmap->vm_ops = &hello_vm_ops;
vma = vmap;
return 0;
}
#else
static int hello_mmap(struct file *file, struct vm_area_struct *vma)
{
struct mm_struct *mm;
unsigned long size;
unsigned long pfn;
int ret;
mm = current->mm;
pfn = page_to_pfn(page);
size = vma->vm_end - vma->vm_start;
if (size > MAX_SIZE) {
printk("map size too large, max size is 0x%x\n", MAX_SIZE);
return -EINVAL;
}
ret = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
if (ret) {
printk("remap_pfn_range fail\n");
return -EAGAIN;
}
return ret;
}
#endif
static loff_t hello_llseek(struct file *file, loff_t offset, int whence)
{
loff_t pos;
switch(whence) {
case SEEK_SET:
pos = offset;
break;
case SEEK_CUR:
pos = file->f_pos + offset;
break;
case SEEK_END:
pos = MAX_SIZE + offset;
break;
default:
return -EINVAL;
}
if (pos < 0 || pos > MAX_SIZE)
return -EINVAL;
file->f_pos = pos;
return pos;
}
static const struct file_operations hello_chrdev_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release= hello_release,
.read = hello_read,
.write = hello_write,
.mmap = hello_mmap,
.llseek = hello_llseek
};
static int __init hello_init(void)
{
int ret;
ret = alloc_chrdev_region(&devno, 0, 1, "hello"); /* /proc/devices/hello */
if (ret) {
printk("alloc_chrdev_region fail\n");
return ret;
}
hello_cdev = cdev_alloc();
cdev_init(hello_cdev, &hello_chrdev_fops);
ret = cdev_add(hello_cdev, devno, 1);
if (ret) {
printk("cdev_add fail\n");
return ret;
}
hello_class = class_create(THIS_MODULE, "hello-class"); /* /sys/class/hello-clss */
if (IS_ERR(hello_class)) {
printk("create class fail\n");
return -1;
}
hello_device = device_create(hello_class, NULL, devno, NULL, "hello_dev"); /* /dev/hello_dev */
if (IS_ERR(hello_device)) {
printk("create class fail\n");
return -1;
}
return 0;
}
static void __exit hello_exit(void)
{
cdev_del(hello_cdev);
device_unregister(hello_device);
class_destroy(hello_class);
unregister_chrdev_region(devno, 1);
}
module_init( hello_init );
module_exit( hello_exit );
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "xxx" );
mmap_app
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
char write_buf[512];
char read_buf[512];
int main(void)
{
int fd;
char *mmap_adar;
pid_t pid;
fd = open("/dev/hello_dev", O_RDWR);
if (fd < 0) {
printf("open fail\n");
return -1;
}
mmap_adar = (char *)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
memcpy(mmap_adar, "1234", strlen("1234")); // page fault
pid = getpid();
printf("fd %d pid %d\n", fd, pid);
snprintf(write_buf, sizeof(write_buf), "%d", pid);
printf("write_buf %s\n", write_buf);
write(fd, write_buf, strlen(write_buf) + 1);
lseek(fd, 0, SEEK_SET);
read(fd, read_buf, 100);
printf("read buffer %s\n", read_buf);
printf("mmap read %s\n", mmap_adar);
munmap(mmap_adar, 4096);
pause();
printf("end\n");
return 0;
}