Messages in this thread | | | Subject | mmap system call error -- source code attached | Date | Mon, 27 Sep 2004 19:16:25 +0530 | From | "Srinivas G." <> |
| |
Dear all,
I developed a small character device driver. It should work for reading/writing from RAM. I implemented the mmap functionality in this device driver. It is very small program. Even though, I was unable to read the contents from the mapped area.
System configuration is: Intel x86 architecture and Red Hat 7.3 with 2.4.18-3 kernel version.
The following code contains the driver code, make file and application (read/write) code.
-- make install command creates the node under /dev directory based on device major number. -- make uninstall command removes the node from the /dev directory. -- write.c is used to write the contents into the device memory. -- read.c is used to the read the contents from the device memory using read system call. -- read_mmap.c is used to read the contents from the device memory using mmap system call.
Here read.c and write.c are working fine where as when I try to read the contents from the device memory using read_mmap.c file I was not getting any thing except NULL, but when I was reading the same device memory using read.c file it works fine.
What was the error? Where is the fault?
Please any help greatly appreciated.
Thanks and regards, Srinivas G
DRIVER CODE -----------
/* Copyright (C) ESN Technologies * - Linux - * * Simple character driver for Memory to show the mmap functionality * Module : mmap_drv.c * Purpose : provides simple read/write operations from memory like * using mmap functionality * * Core OS interface functions of the driver * * Created on 27-09-2004 to handle mmap call back method. */
/* kernel headers */ #include <linux/module.h> /* for everything ... */ #include <linux/init.h> /* explicit init & exit module difinitions */ #include <linux/kernel.h> /* for printk */ #include <linux/fs.h> /* for file and inode structure */ #include <linux/mm.h> /* for vm_area_structure */ #include <linux/slab.h> /* for kmalloc */ #include <asm/uaccess.h> /* for copy_to_user and copy_from_user */ #include <asm/io.h> /* for virt_to_phys API */
/* driver name in the /proc/devices and maximum devices */ #define MMAP_MODULE_NAME "mmap-drv" #define MAX_TYPE 1 #define MAX_MEM_SIZE (1024*102) /* maximum memory allocated */
/* debugging */ #ifdef MMAP_DBG #define PRINTK(fmt, arg...) printk("MMAP_DBG <%s> "fmt,__FUNCTION__,##arg) #else #define PRINTK(fmt, arg...) while(0) #endif
/* declare a pointer to hold the allocated memory */ unsigned char *mapped_area; struct rw_semaphore mmap_sem;
/* function prototypes */ static loff_t mmap_llseek(struct file *, loff_t, int); static int mmap_open(struct inode *, struct file *); static int mmap_close(struct inode *, struct file *); static ssize_t mmap_read(struct file *, char *, size_t, loff_t *); static ssize_t mmap_write(struct file *, const char *, size_t, loff_t *); static int mmap_mmap(struct file *, struct vm_area_struct *);
/* file operations structure, callback functions! */ static struct file_operations mmap_fops = { owner: THIS_MODULE, llseek: mmap_llseek, open: mmap_open, release: mmap_close, read: mmap_read, write: mmap_write, mmap: mmap_mmap, };
/* driver major number */ static int mmap_maj = 230;
MODULE_AUTHOR("SRINIVAS G"); MODULE_DESCRIPTION("Character Memory Device Driver to handle MMAP"); MODULE_LICENSE("GPL");
************************************************************************ **** /* * mmap_open(): open callback function. */ static int mmap_open(struct inode *inode, struct file *filp) { /* get the minor number from inode structure */ unsigned int minor = MINOR(inode->i_rdev);
PRINTK("callback invoked!\n"); /* check whether the minor number is existed within the range */ if(minor > MAX_TYPE) return -ENODEV; /* * put the address of file_operations structure in the * f_op variable of file structure */ filp->f_op = &mmap_fops; /* increment the usage count */ MOD_INC_USE_COUNT; return 0; } ************************************************************************ ****
/* * mmap_close(): release callback function. */ static int mmap_close(struct inode *inode, struct file *filp) { PRINTK("callback invoked!\n"); /* decrement the usage count */ MOD_DEC_USE_COUNT;
return 0; } ************************************************************************ ****
/* * mmap_read(): read callback function. */ static int mmap_read(struct file *filp, char *buff, size_t count, loff_t *f_pos) { ssize_t ret = 0,esnind;
/* get the minor number */ int minor = MINOR(filp->f_dentry->d_inode->i_rdev); PRINTK("callback invoked!\n"); /* check whether the minor number is existed within the range */ if(minor > MAX_TYPE) return -ENODEV; /* to check whether the file position is at the end of the memory */ if(*f_pos >= MAX_MEM_SIZE) return ret;
/* Is file position and count reaches to the end of memory */ if(*f_pos + count > MAX_MEM_SIZE) count = MAX_MEM_SIZE - *f_pos; /* copy the contents from kernel space to user space */ if (copy_to_user(buff,mapped_area,count)) ret = -EFAULT;
/* change the file position accordingly */ *f_pos += count; ret = count; return ret; } ************************************************************************ ****
/* * mmap_write(): write callback function. */ static int mmap_write(struct file *filp, const char *buff, size_t count, loff_t *f_pos) { ssize_t ret = 0,esnind; /* get the minor number */ int minor = MINOR(filp->f_dentry->d_inode->i_rdev); PRINTK("callback invoked!\n");
/* check whether the minor number is existed within the range */ if(minor > MAX_TYPE) return -ENODEV; /* to check whether the file position is at the end of the memory */ if(*f_pos >= MAX_MEM_SIZE) return ret;
/* Is file position and count reaches to the end of memory */ if(*f_pos + count > MAX_MEM_SIZE) count = MAX_MEM_SIZE - *f_pos; /* copy the contents from user space to kernel space */ if (copy_from_user(mapped_area,buff,count)) ret = -EFAULT; /* change the file position accordingly */ *f_pos += count; ret = count; return ret; } ************************************************************************ ****
/* * mmap_mmap(): write callback function. */ static int mmap_mmap(struct file *filp, struct vm_area_struct *vma) { int ret =0, pages; unsigned long physic_addr, start, size, next; int minor = MINOR(filp->f_dentry->d_inode->i_rdev); PRINTK("callback invoked!\n"); /* check whether the minor number is existed within the range */ if(minor > MAX_TYPE) return -ENODEV;
start = vma->vm_start; physic_addr = virt_to_phys(mapped_area); pages = MAX_MEM_SIZE / PAGE_SIZE; size = vma->vm_end - vma->vm_start; next = MAX_MEM_SIZE + PAGE_SIZE;
printk("mapped area virtual address is : %08x!\n", mapped_area);
printk("mapped area physical address : %08x!\n", physic_addr); if (size > next) return -EINVAL;
vma->vm_flags |= VM_LOCKED;
down_write(&mmap_sem);
while(pages--) { if (remap_page_range(start,physic_addr,PAGE_SIZE,vma->vm_page_prot)) { ret = -EAGAIN; break; } if (size <= PAGE_SIZE) break;
size -= PAGE_SIZE; start += PAGE_SIZE; }
up_write(&mmap_sem);
return ret; } ************************************************************************ ****
/* * mmap_llseek(): lseek callback function. */ static loff_t mmap_llseek(struct file *filp, loff_t off, int whence) { loff_t newpos;
PRINTK("callback invoked!\n"); switch(whence) { case 0: /* SEEK_SET */ newpos = off; break;
case 1: /* SEEK_CUR */ newpos = filp->f_pos + off; break;
case 2: /* SEEK_END */ newpos = MAX_MEM_SIZE + off; break; default: return -EINVAL; }
if (newpos<0) return -EINVAL;
filp->f_pos = newpos;
return newpos; }
************************************************************************ ****
/* * Module entry point */ static int __init mmap_init(void) { int result;
PRINTK("invoked!\n");
/* * register the MMAP device with major number, name and * pointer to file_operations structure */ if( (result=register_chrdev(mmap_maj,MMAP_MODULE_NAME,&mmap_fops)) < 0) { printk(KERN_ALERT "MMAP ERROR | could NOT register device!\n"); return result; } /* allocate the memory for Device to read/write */ mapped_area = (char *)kmalloc((MAX_MEM_SIZE),GFP_KERNEL);
if(mapped_area == NULL) { printk("INFO | MMAP kmalloc(%d) fail!\n",MAX_MEM_SIZE); return -ENOMEM; } /* initialize the allocated memory */ memset(mapped_area, 0, MAX_MEM_SIZE); return 0; } ************************************************************************ ****
/* * Module exit point */ static void __exit mmap_cleanup(void) { PRINTK("invoked!\n"); /* unregister the device with specified major number */ if(unregister_chrdev(mmap_maj,MMAP_MODULE_NAME) < 0) printk("MMAP ERROR | Could NOT unregister the device!\n");
kfree(mapped_area); }
/* module init/exit macros */ module_init(mmap_init); module_exit(mmap_cleanup); ************************************************************************ **** ************************************************************************ ****
MAKE FILE --------- # # Makefile for FIFO Driver for Memory. #
INCDIR=/usr/src/linux-2.4/include # Include path on RedHat
DEVICE=esn_mmap MAJOR =230 TARGET=mmap_device.o OBJS=mmap_drv.o
#CFLAGS=-DMODULE -D__KERNEL__ -I$(INCDIR) -Wstrict-prototypes -fomit-frame-pointer -O2
### Enable Debugging ### CFLAGS=-DMODULE -D__KERNEL__ -DMMAP_DBG -I$(INCDIR) -Wstrict-prototypes -fomit-frame-pointer -O2
$(TARGET): $(OBJS) $(LD) -r -o $(TARGET) $(OBJS)
clean: $(RM) $(TARGET) $(OBJS)
install: @mknod /dev/$(DEVICE)0 c $(MAJOR) 0
uninstall: @$(RM) /dev/$(DEVICE)*
************************************************************************ **** ************************************************************************ ****
WRITE.C -------
/* * Description: * This program is used to write the specified number of characters * into the specified character device * * Command line arguments: * - actual executable file name * - Character device name * - character string without spaces * * Return value: * - positive number or 0 on success * - negative number on failure */
#include <stdio.h> #include <fcntl.h> #include <sys/stat.h> #include <string.h>
int main (int argc, char *argv[]) { int fd, count,i; char buff[100]; size_t write_count;
/* check whether the no.of arguments are correct or not */ if(argc < 3) { printf("\n USAGE : <file_name> <device_name> <string>\n\n"); printf("\n Example : ./write /dev/esn_mmap0 srinivas_esn\n\n"); return; } /* opening the specified device from argument 1 */ fd = open(argv[1], O_WRONLY);
if (fd < 0) { printf("Unable to open the specidifed file!\n"); return; }
/* count the total no.of chars from argument 2 */ write_count = strlen(argv[2]); /* writing the contents into the device */ if ( (count = write(fd, argv[2], write_count)) > 0) printf("\nThe contents are written successfulle!\n\n"); else printf("\nThe contents are not written into the file!\n\n");
return 0; } ************************************************************************ **** ************************************************************************ ****
READ.C ------ /* * Description: * This program is used to read the specified number of characters * from specified character device * * Command line arguments: * - actual executable file name * - Character device name * - No. of characters to read * * Return value: * - positive number or 0 on success * - negative number on failure */
#include <stdio.h> #include <fcntl.h> #include <sys/stat.h>
int main (int argc, char *argv[]) { int fd, count,i; char buff[100]; size_t read_count; if(argc < 3) { printf("\n USAGE : <file_name> <device_name> <no.of chars to read>\n\n"); printf("\n Example : ./read /dev/esn_mmap0 11\n\n"); return; } /* opening the specified device from argument 1 */ fd = open(argv[1], O_RDONLY);
if (fd < 0) { printf("Unable to open the specidifed file!\n"); return; }
/* converting the argument 2 (no.of chars to read) into interger */ sscanf(argv[2],"%d",&read_count);
/* reading the contents from device */ if ( (count = read(fd, buff, read_count)) > 0) { printf("The contents are : "); for (i = 0; i < read_count; i++) printf("%c",buff[i]); printf("\n"); } else printf("The contents are not available in the file!\n");
return 0; } ************************************************************************ **** ************************************************************************ ****
READ_MMAP.C -----------
/* * Description: * This program is used to read the specified number of characters * from specified character device using mmap system call. * * Command line arguments: * - actual executable file name * - Character device name * - No. of characters to read * * Return value: * - positive number or 0 on success * - negative number on failure */
#include <stdio.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h> /* for mmap system call */ #define MAX_MEM_SIZE (1024*102)
int main (int argc, char *argv[]) { int fd, count,i; char buff[100]; size_t read_count; unsigned char *app_mapped_area; if(argc < 3) { printf("\n USAGE : <file_name> <device_name> <no.of chars to read>\n\n"); printf("\n Example : ./read_mmap /dev/esn_mmap0 11\n\n"); return; } /* opening the specified device from argument 1 */ fd = open(argv[1], O_RDONLY);
if (fd < 0) { printf("Unable to open the specidifed file!\n"); return; }
/* converting the argument 2 (no.of chars to read) into interger */ sscanf(argv[2],"%d",&read_count);
app_mapped_area = (unsigned char *)mmap(0,MAX_MEM_SIZE,PROT_READ,MAP_SHARED,fd,0); if (app_mapped_area == MAP_FAILED) { printf("mmap system call failed!\n"); return -1; } printf("The mmapped address is %08x!\n",app_mapped_area); for (i = 0; i < read_count; i++) { printf("Inside FOR loop ....!\n"); printf("%c",*app_mapped_area++); }
return 0; } ************************************************************************ **** ************************************************************************ ****
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |