By liran bh | 5/16/2016 | Linux Kernel & Internals

Complex Character driver

Kernel Code:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/gfp.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/kdev_t.h>
#include <linux/proc_fs.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/mempool.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <linux/interrupt.h>    /* We want an interrupt */
 
#define PHY_IO_ADD 0x101e8000
#define HW_BUF_SIZE 64
#define NUMOBJS 100
#define BLOCKSIZE 128
#define MYNAME "driver/my_proc_file"
 
DECLARE_MUTEX(mt);
 
struct mydevicestatus
{
    int r1;
    int r2;
    int r3;
};
 
static char *clipstack[100];
static int clipstop = -1;
 
static int acme_count = 1;
static dev_t acme_dev;
 
static struct cdev *acme_cdev;
 
static struct proc_dir_entry *myproc = NULL;
struct kmem_cache *clips;
mempool_t *pool;
static char msg[100];
 
static ssize_t
acme_read(struct file *file, char __user *buf,size_t count,loff_t *ppos)
{
    int len;
    if(*ppos > 0)
    {
        return 0;
    }
    len=strlen(clipstack[clipstop]);
    down(&mt);
   if (copy_to_user(buf /* to */, clipstack[clipstop] /* from */, len)) {
       up(&mt);
      return -EFAULT;
   } else {
       mempool_free(clipstack[clipstop--],pool);
       *ppos = len;
       up(&mt);
       return len;
   }
}
 
static ssize_t
acme_write(struct file *file1,const char __user *buf,size_t count,loff_t *ppos)
{
    down(&mt);
   clipstack[++clipstop] = mempool_alloc(pool,GFP_KERNEL);
   if (copy_from_user(clipstack[clipstop], buf , count)) {
       up(&mt);
      return -EFAULT;
   } else {
       up(&mt);
      return count;
   }
 
}
 
static int device_ioctl(struct inode *inode,struct file*file,unsigned int num,
        unsigned long param)
{
    unsigned int r;
    int (*fptr)(int);
    int fr;
    struct mydevicestatus st;
    switch(num)
    {
        case 10:
                __get_user(r,(int *)param);
                printk("ioctl num=%u int pointer=%u\n",num,r);
                break;
        case 20:
                fptr = (int(*)(int))param;
                fr=fptr(100);
                printk("res=%d\n",fr);
                //mempool_resize(pool,param,0);
                break;
        case 30:
                copy_from_user(&st,(void *)param,sizeof(struct mydevicestatus));
                printk("ioctl struct r1=%d, r2=%d, r3=%d\n",st.r1,st.r2,st.r3);
                break;
    }
    return 0;
}
 
static int device_mmap(struct file *file,struct vm_area_struct* vma)
{
    int size;
    size=vma->vm_end - vma->vm_start;
    if(remap_pfn_range(vma,vma->vm_start,PHY_IO_ADD>>PAGE_SHIFT,size,vma->vm_page_prot))
        return -EAGAIN;
    return 0;
}
 
static struct file_operations acme_fops =
{
    .owner = THIS_MODULE,
    .read = acme_read,
    .write = acme_write,
    .ioctl = device_ioctl,
    .mmap = device_mmap
};
 
int myread(char *page,char **start,off_t off,int count,int *eof,void *data)
{
    int len =0;
    if(off <= 0){
        len=sprintf(page,"msg=%s\n",msg);
    }
    return len;
}
 
int mywrite(struct file *file, const char *buffer, unsigned long count,
           void *data)
{
    if ( copy_from_user(msg, buffer, count) ) {
        return -EFAULT;
    }
    msg[count] = 0;
    return count;
}
 
static int
hello_init (void)
{
    clips=kmem_cache_create("clips",BLOCKSIZE,BLOCKSIZE,0,NULL);
    pool = mempool_create(NUMOBJS,mempool_alloc_slab,mempool_free_slab,clips);
 
    acme_dev = MKDEV(237,0);
    register_chrdev_region(acme_dev,1,"acme 2");
 
    acme_cdev=cdev_alloc();
    if(!acme_cdev)
    {
        printk (KERN_INFO "cdev alloc error.\n");
         return -1;
    }
    acme_cdev->ops = &acme_fops;
    acme_cdev->owner = THIS_MODULE;
 
    if(cdev_add(acme_cdev,acme_dev,acme_count))
    {
        printk (KERN_INFO "cdev add error.\n");
         return -1;
    }
      myproc = create_proc_entry(MYNAME,0,NULL);
      myproc->read_proc = myread;
      myproc->write_proc = mywrite;
 
  return 0;
 
}
 
static void
hello_cleanup (void)
{
    cdev_del(acme_cdev);
    unregister_chrdev_region(acme_dev, acme_count);
    remove_proc_entry(MYNAME,NULL);
    kmem_cache_destroy(clips);
    mempool_destroy(pool);
}
 
module_init (hello_init);
module_exit (hello_cleanup);
MODULE_LICENSE("GPL");

 

User Code

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
 
#define SIZE 64
 
struct mydevicestatus
{
    int r1;
    int r2;
    int r3;
};
 
int userfn(int v)
{
    return v+100;
}
 
int main()
{
    char buf[100];
    struct mydevicestatus status1={33,44,55};
    int fd;
    int m=100;
    int *map;
 
    fd=open("/dev/mydev",O_RDWR);
 
    //read(fd,buf,100);
 
    ioctl(fd,10,&m);
 
    ioctl(fd,20,userfn);
 
    ioctl(fd,30,&status1);
 
    map = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
 
    printf("RTC=%d\n",map[0]);
    sleep(3);
    printf("RTC=%d\n",map[0]);
 
    return 1;
}

 

 

 

 

 

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now