linux mmap实例_linux驱动之mmap实例

// Linux Device Driver Template/Skeleton with mmap

// Kernel Module

#include #include #include #include #include #include #include #include #include #include #include #include #include

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)

#include #endif

#define SKELETON_MAJOR 240

#define SKELETON_NAME "skeleton"

#define CASE1 1

#define CASE2 2

static unsigned int counter = 0;

static char string [128];

static int data;

//#define USEASCII

#ifdef USEASCII

static char *kmalloc_area = NULL;

static char *kmalloc_ptr = NULL;

#else

static unsigned int *kmalloc_area = NULL;

static unsigned int *kmalloc_ptr = NULL;

#endif

#define LEN (64*1024)

unsigned long virt_addr;

DECLARE_WAIT_QUEUE_HEAD(skeleton_wait);

static int data_not_ready = 0;

// open function - called when the "file" /dev/skeleton is opened in userspace

static int skeleton_open (struct inode *inode, struct file *file) {

printk("skeleton_openn");

// we could do some checking on the flags supplied by "open"

// i.e. O_NONBLOCK

// -> set some flag to disable interruptible_sleep_on in skeleton_read

return 0;

}

// close function - called when the "file" /dev/skeleton is closed in userspace

static int skeleton_release (struct inode *inode, struct file *file) {

printk("skeleton_releasen");

return 0;

}

// read function called when from /dev/skeleton is read

static ssize_t skeleton_read (struct file *file, char *buf,

size_t count, loff_t *ppos) {

int len, err;

// check if we have data - if not, sleep

// wake up in interrupt_handler

while (data_not_ready) {

interruptible_sleep_on(&skeleton_wait);

}

//data_not_ready = 1;

if( counter <= 0 )

return 0;

err = copy_to_user(buf,string,counter);

if (err != 0)

return -EFAULT;

len  = counter;

counter = 0;

return len;

}

// write function called when to /dev/skeleton is written

static ssize_t skeleton_write (struct file *file, const char *buf,

size_t count, loff_t *ppos) {

int err;

err = copy_from_user(string,buf,count);

if (err != 0)

return -EFAULT;

counter += count;

return count;

}

// ioctl - I/O control

static int skeleton_ioctl(struct inode *inode, struct file *file,

unsigned int cmd, unsigned long arg) {

int retval = 0;

switch ( cmd ) {

case CASE1:/* for writing data to arg */

if (copy_from_user(&data, (int *)arg, sizeof(int)))

return -EFAULT;

break;

case CASE2:/* for reading data from arg */

if (copy_to_user((int *)arg, &data, sizeof(int)))

return -EFAULT;

break;

default:

retval = -EINVAL;

}

return retval;

}

#ifndef VMALLOC_VMADDR

#define VMALLOC_VMADDR(x) ((unsigned long)(x))

#endif

// From: http://www.scs.ch/~frey/linux/memorymap.html

volatile void *virt_to_kseg(volatile void *address) {

pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte;

unsigned long va, ret = 0UL;

va=VMALLOC_VMADDR((unsigned long)address);

/* get the page directory. Use the kernel memory map. */

pgd = pgd_offset_k(va);

/* check whether we found an entry */

if (!pgd_none(*pgd)) {

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)

/* get the page middle directory */

pmd = pmd_offset(pgd, va);

#else

// I'm not sure if we need this, or the line for 2.4

//    above will work reliably too

// If you know, please email me :-)

pud_t *pud = pud_offset(pgd, va);

pmd = pmd_offset(pud, va);

#endif

/* check whether we found an entry */

if (!pmd_none(*pmd)) {

/* get a pointer to the page table entry */

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)

ptep = pte_offset(pmd, va);

#else

ptep = pte_offset_map(pmd, va);

#endif

pte = *ptep;

/* check for a valid page */

if (pte_present(pte)) {

/* get the address the page is refering to */

ret = (unsigned long)page_address(pte_page(pte));

/* add the offset within the page to the page address */

ret |= (va & (PAGE_SIZE -1));

}

}

}

return((volatile void *)ret);

}

static int skeleton_mmap(struct file * filp, struct vm_area_struct * vma) {

int ret;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)

ret = remap_page_range(vma->vm_start,

virt_to_phys((void*)((unsigned long)kmalloc_area)),

vma->vm_end-vma->vm_start,

PAGE_SHARED);

//          vma->vm_page_prot);

#else

ret = remap_pfn_range(vma,

vma->vm_start,

virt_to_phys((void*)((unsigned long)kmalloc_area)) >> PAGE_SHIFT,

vma->vm_end-vma->vm_start,

PAGE_SHARED);

//               vma->vm_page_prot);

#endif

if(ret != 0) {

return -EAGAIN;

}

return 0;

}

// define which file operations are supported

struct file_operations skeleton_fops = {

.owner = THIS_MODULE,

.llseek = NULL,

.read  = skeleton_read,

.write = skeleton_write,

.readdir = NULL,

.poll  = NULL,

.ioctl = skeleton_ioctl,

.mmap  = skeleton_mmap,

.open  = skeleton_open,

.flush = NULL,

.release = skeleton_release,

.fsync = NULL,

.fasync = NULL,

.lock  = NULL,

//.readv = NULL,

//.writev = NULL,

};

// initialize module

static int __init skeleton_init_module (void) {

int i;

#ifndef USEASCII

int tmp, tmp2;

#endif

printk("initializing modulen/n");

i = register_chrdev (SKELETON_MAJOR, SKELETON_NAME, &skeleton_fops);

if (i != 0) return - EIO;

// reserve memory with kmalloc - Allocating Memory in the Kernel

kmalloc_ptr = kmalloc(LEN + 2 * PAGE_SIZE, GFP_KERNEL);

if (!kmalloc_ptr) {

printk("kmalloc failedn/n");

return 0;

}

#ifdef USEASCII

kmalloc_area = (char *)(((unsigned long)kmalloc_ptr + PAGE_SIZE -1) & PAGE_MASK);

#else

kmalloc_area = (unsigned int *)(((unsigned long)kmalloc_ptr + PAGE_SIZE -1) & PAGE_MASK);

#endif

for (virt_addr=(unsigned long)kmalloc_area; virt_addr < (unsigned long)kmalloc_area + LEN;

virt_addr+=PAGE_SIZE) {

// reserve all pages to make them remapable

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)

mem_map_reserve(virt_to_page(virt_addr));

#else

SetPageReserved(virt_to_page(virt_addr));

#endif

}

printk("kmalloc_area at 0x%p (phys 0x%lx)/n", kmalloc_area,

virt_to_phys((void *)virt_to_kseg(kmalloc_area)));

#ifdef USEASCII

// fill allocated memory with 0123456789 ascii

for( i = 48; i < 58; i++) {

kmalloc_ptr[i-48] = (char)i;

}

i = 0;

kmalloc_ptr[58-48] = (char)i;

#else

// fill allocated memory with integers

tmp = sizeof(int);

for( i = 0; i < (10 * tmp); i = i + tmp) {

kmalloc_ptr[i] = (unsigned int)i;

tmp2 = (unsigned int)kmalloc_ptr[i];

printk("kmalloc_ptr[%d]=%d/n", i, tmp2);

}

#endif

return 0;

}

// close and cleanup module

static void __exit skeleton_cleanup_module (void) {

printk("cleaning up modulen");

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)

for (virt_addr=(unsigned long)kmalloc_area; virt_addr < (unsigned long)kmalloc_area + LEN;

virt_addr+=PAGE_SIZE) {

// clear all pages

ClearPageReserved(virt_to_page(virt_addr));

}

#endif

kfree(kmalloc_ptr);

unregister_chrdev (SKELETON_MAJOR, SKELETON_NAME);

}

module_init(skeleton_init_module);

module_exit(skeleton_cleanup_module);

MODULE_AUTHOR("www.captain.at");

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("Linux Device Driver Template with MMAP");

---------------Makefile----------------------

obj-m:=skeleton.o

-----------------测试程序----------------------

// Linux Device Driver Template/Skeleton with mmap

// Userspace test program

#include #include #include #include #include #include #include

#define CASE1 1

#define CASE2 2

#define BUFSIZE 64*1024

//extern  void hello(void);

extern  global;

//#define USEASCII

main() {

int i, fd, len, wlen, tmp, tmp2;

char string[] = "Skeleton Kernel Module Test";

char receive[128];

int data, rdata;

char * mptr;

size_t size = BUFSIZE;

#ifdef USEASCII

printf("USEASCII/n");

char buffer[BUFSIZE];

#else

printf("NO  USEASCII/n");

unsigned int buffer[BUFSIZE];

#endif

printf("global=%d/n",global);

hello();

printf("global=%d/n",global);

fd = open("/dev/skeleton", O_RDWR | O_SYNC);

if( fd == -1) {

printf("open error.../n");

exit(0);

}

// test device write function

wlen = strlen(string) + 1;

len = write(fd, string, wlen);

if( len == -1 ) {

printf("write error.../n");

exit(1);

}

printf("String '%s' written to /dev/skeleton/n", string);

// test device read function

len = read(fd, receive, 128);

if( len == -1 ) {

printf("read error...n");

exit(1);

}

printf("String '%s' read from /dev/skeleton/n", receive);

// test mmap

mptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);

if(mptr == MAP_FAILED) {

printf("mmap() failed/n");

exit(1);

}

// write something into the kernel device driver memory allocated by kmalloc

// memcpy(mptr, "Hello World!", 13);

// clear our local buffer

memset(buffer, 0, size);

// read from the kmalloc area in kernel space

memcpy(buffer, mptr, size-1);

#ifdef USEASCII

printf("mmap: '%s'/n", buffer);

#else

tmp = sizeof(int);

for( i = 0; i < (10 * tmp); i = i + tmp) {

tmp2 = (unsigned int)buffer[i];

printf("buffer[%d]=%d/n", i, tmp2);

}

#endif

// test ioctl

data = 0x55555555;

ioctl(fd, CASE1, &data);

ioctl(fd, CASE2, &rdata);

printf("IOCTL test: written: '%x' - received: '%x'/n", data, rdata);

munmap(mptr, size);

close(fd);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值