LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-24-2008, 06:06 AM   #1
unitedroad
LQ Newbie
 
Registered: Jan 2008
Posts: 8

Rep: Reputation: 0
Copy_to_user returns a zeroed out string in a scull like driver


Hello everyone, I am trying to write a scull like dummy device driver. I have written it almost exactly like in the book but I haven't enabled semaphore locking and IOCTL calls. The problem I am facing is that the write method seems to work fine, but the read method returns a zeroed out string. Copy_to_user seems to return this zeroed out buffer, but if I use printk to find out what I have in the quantum, then I can see that it has the data written to it by copy_from_user.
Here is the code from readmemorydriver.c :

Code:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include "readmemorydriver.h"
#include <linux/kernel.h>
#include <asm/uaccess.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("0.1");

dev_t devno;
unsigned int count = 5;
unsigned int major = SCULL_MAJOR;
unsigned int firstminor=0;
unsigned char *name = "readmemory";
unsigned int scull_nr_devs = 1;
struct scull_dev *scull_devices;
unsigned int scull_quantum = SCULL_QUANTUM;
unsigned int scull_qset = SCULL_QSET;


loff_t scull_llseek(struct file *filp, loff_t off, int whence){
    return 0;
}

int scull_release(struct inode *inode, struct file *filep){
    return 0;
}

int scull_ioctl(struct inode *inode, struct file *filp, unsigned int icmd, unsigned long arg){
    return 0;
} 

struct struct_qset *scull_follow(struct scull_dev *scull_dev, int qsetnum){
    int i;
    if (!scull_dev)
	return NULL;
    struct struct_qset *struct_qset = scull_dev->quantum_data; //find 0th 
    printk(KERN_ALERT "FOLLOW: qsetnum = %d, struct_qset = %u \n", qsetnum, struct_qset );
    if(!struct_qset){
	struct_qset = scull_dev->quantum_data = (struct struct_qset*) kmalloc(sizeof(struct struct_qset),GFP_KERNEL);
	memset(struct_qset, 0, sizeof(struct struct_qset));
	return struct_qset;
    }
    //element this way 
    for(i = 1; i <= qsetnum; i++){ //qsetnum is the position of the
    				   //wanted qset element - get the element at this position
	if(!struct_qset->next){
	    struct_qset->next = (struct struct_qset*) kmalloc(sizeof(struct struct_qset),GFP_KERNEL);
	    memset(struct_qset->next, 0, sizeof(struct struct_qset));
	    return struct_qset->next;	 
	}
	struct_qset = struct_qset->next;
    }
    return struct_qset;
}


int scull_trim(struct scull_dev *dev){
    int j;
    if (!dev) //B diagnostics, remove later
	return;
    struct struct_qset *next, *qsetptr = dev->quantum_data;
    if (!qsetptr)
	return 0;  //B don't know what I should return
    printk(KERN_ALERT "Value of qsetptr = %u\n", qsetptr);
    char **data; 
    while(qsetptr ){
        data = qsetptr->data;		
	if(data){
	    for(j=0;j<scull_qset;j++){
	        if(data[j])
		    kfree(data[j]);	
		  //  data[j] = NULL; //B should I really do this or is it not necessary
	    }
	    kfree(data);
	    // data = NULL;
	}
	
	next = qsetptr->next;
	kfree(qsetptr);    
	qsetptr = next;
    }
    dev->size=0;
    dev->quantum_data = NULL;
    return 0;
}

int scull_open(struct inode *inode, struct file *filp){
    struct scull_dev *scull_dev;
    scull_dev = container_of(inode->i_cdev, struct scull_dev,cdev);
    if((filp->f_flags & O_ACCMODE)==O_WRONLY){
		scull_trim(scull_dev);	
    }
    filp->private_data =   scull_dev; 
    return 0;
}

ssize_t scull_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos){
    struct scull_dev *scull_dev = filep->private_data; 
    struct struct_qset *struct_qset;
    int size, pos; 
    int qsetnum, qsetpos;
    int quantumnum, quantumpos;
    int retval = -ENOMEM;
    size =  scull_dev->size;
    pos = *f_pos; 
    qsetnum = size/scull_qset;
    qsetpos = size%scull_qset;
    quantumnum = qsetpos/scull_quantum;
    quantumpos = qsetpos%scull_quantum;	
    struct_qset = scull_follow(scull_dev, qsetnum);	
    if(!struct_qset)
	    goto out;
    if(!struct_qset->data)
        struct_qset->data = kmalloc(scull_qset*(sizeof(void*)),GFP_KERNEL);	
    if(!struct_qset->data)
        goto out;
    memset(struct_qset->data, 0, scull_qset*(sizeof(void*)));
    if(!struct_qset->data[quantumnum])
	struct_qset->data[quantumnum] = kmalloc(scull_quantum*(sizeof(char)),GFP_KERNEL);
    if(!struct_qset->data[quantumnum])
	goto out;
    memset(struct_qset->data[quantumnum], 0, scull_quantum*(sizeof(char)));
    if (count  > scull_quantum - quantumpos)
	count = scull_quantum - quantumpos;		 
    printk(KERN_ALERT "WRITE: Value of pos = %d, quantumnum = %u, struct_qset->data[quantumnum] = %u, size=%d, count=%d,buf = %s \n",pos, quantumnum, struct_qset->data[quantumnum], size, count, buf); 
    if(copy_from_user(struct_qset->data[quantumnum]+quantumpos, buf, count)){
	retval = -EFAULT;
	goto out;
    }
    printk(KERN_ALERT "WRITE: quantum = %s\n", struct_qset->data[quantumnum]);
    *f_pos = pos + count;
    if (size < *f_pos )
	scull_dev->size = pos + count;
    return count;

    out:
	return retval;

}



ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos){
    struct scull_dev *scull_dev  = filp->private_data;
    struct struct_qset *struct_qset ;
    int size, pos = *fpos; 
    int retval = 0;
    int qsetnum, qsetpos;
    int quantumnum, quantumpos;
    size = scull_dev->size;
    pos = *fpos;
    if (size <= pos)
	goto out; 
    if (count > size - pos)
	count = size - pos; 
    qsetnum = size/scull_qset;
    qsetpos = size%scull_qset;
    quantumnum = qsetpos/scull_quantum;
    quantumpos = qsetpos%scull_quantum;
    struct_qset = scull_follow(scull_dev, qsetnum); 
    if(count>scull_quantum - quantumpos)
	count = scull_quantum - quantumpos;
    if(!struct_qset||!struct_qset->data||!struct_qset->data[quantumnum]){
	goto out;
    }
    
    printk(KERN_ALERT "READ: Value of pos = %d, quantumnum = %u, struct_qset->data[quantumnum] = %u, size=%d, count = %d, buf = %s\n",pos, quantumnum, struct_qset->data[quantumnum], size, count, buf); 
    if(copy_to_user(buf, struct_qset->data[quantumnum]+quantumpos, count)){    
	retval = -EFAULT;
	goto out;
    } 
    printk(KERN_ALERT "READ: Value of pos = %d, quantumnum = %u, struct_qset->data[quantumnum] = %u, size=%d, count = %d, buf = %s\n",pos, quantumnum, struct_qset->data[quantumnum], size, count, buf); 
    printk(KERN_ALERT "READ: quantum = %s", struct_qset->data[quantumnum]);
    *fpos = pos + count; 
    return count;
    
    out:
	return retval;
}

struct file_operations scull_fops = {
	.owner = THIS_MODULE,
	.open = scull_open,
	.llseek = scull_llseek,
	.write = scull_write,
	.read = scull_read,
	.release = scull_release,
	.ioctl = scull_ioctl,
};

static void scull_setup_cdev(struct scull_dev *dev, int index){
   int err, devno = MKDEV(major, firstminor + index);
   cdev_init(&dev->cdev, &scull_fops);  
   dev->cdev.owner = THIS_MODULE;
   err = cdev_add(&dev->cdev, devno,1);
   if(err)
	printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}

void read_memory_exit(){
    int i;
    if(scull_devices){
	for (i = 0; i < scull_nr_devs; i++){
	    cdev_del(&scull_devices[i].cdev); 
	    scull_trim(&scull_devices[i]);
	} 
	kfree(scull_devices); 
	unregister_chrdev_region(devno,count); 
    }
}

int __init read_memory_init(){
//    read_memory;
/*    int major = 12;
    int minor = 0; 
    devno = MKDEV(major, minor);
*/
    int i, result;
    if(!major){
	result =  alloc_chrdev_region(&devno, 0,count, "readmemory" );
        major = MAJOR(devno);
    } else {
	result = register_chrdev_region(devno, count,"readmemory");
    }
    if(result < 0){
	printk(KERN_ALERT "error in allocating device");
	return result;
    }
    scull_devices = kmalloc(scull_nr_devs*sizeof(struct scull_dev), GFP_KERNEL);
    if(!scull_devices){
	result = -ENOMEM;
	goto fail;
    }

    memset(scull_devices, 0, scull_nr_devs*sizeof(struct scull_dev));

    for (i = 0; i < scull_nr_devs;i++){
	scull_devices[i].quantum = scull_quantum;
	scull_devices[i].qset = scull_qset;
	init_MUTEX(&scull_devices[i].sem);
	// printk(KERN_ALERT "VALUE OF quantum_data is %u", scull_devices[i].quantum_data);
	scull_setup_cdev(&scull_devices[i], i);	 	
    }	 
    
    return 0;

    fail:
	read_memory_exit();
	return result;
}

 



/*read_memory(){
    int *krnlprt = 0x0c000001;
    return *krnlprt;
}
*/

module_init(read_memory_init);
module_exit(read_memory_exit);
Here is the readmemorydriver.h file :

Code:
#ifndef READMEMORYDRIVER_H
#define READMEMORYDRIVER_H

#ifndef CDEV_H
#define CDEV_H
#include <linux/cdev.h>
#endif

#ifndef SCULL_MAJOR
#define SCULL_MAJOR 0
#endif

#ifndef SCULL_QUANTUM
#define SCULL_QUANTUM 4000
#endif

#ifndef SCULL_QSET 
#define SCULL_QSET 1000
#endif

int scull_open (struct inode*, struct file*);
loff_t scull_llseek (struct file*, loff_t, int);
ssize_t scull_write (struct file*, const char __user*, size_t, loff_t*);
ssize_t scull_read (struct file*, char __user*, size_t, loff_t*);
int scull_release (struct inode*, struct file*);
int scull_ioctl (struct inode*, struct file*, unsigned int, unsigned long);

struct struct_qset{
    char **data;
    struct struct_qset *next;
};

struct scull_dev {
    struct struct_qset *quantum_data;
    int quantum;
    int qset;
    unsigned long size;
  /*sem and accesskey to be used later as the driver goes further */
    struct semaphore sem; 
    struct cdev cdev;
};





#endif
I am not able to understand why copy_to_user is not able to fetch my data. Please help me with it as it will help me in avoiding this problem in future.
thanks in advance
Dhruwat

Last edited by unitedroad; 12-24-2008 at 10:04 AM. Reason: adding code for readmemorydriver.h
 
Old 12-25-2008, 05:59 AM   #2
unitedroad
LQ Newbie
 
Registered: Jan 2008
Posts: 8

Original Poster
Rep: Reputation: 0
Hi everyone, it was a problem with my code hwere I was taking the offest in the qset data structure. I divided size by quantum*qset whereas I should have used the *f_pos as the dividend.
It is now working fine.
Thanks
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
ioread32 returns 0xffffffff; pci driver niteshg Linux - General 3 12-02-2009 04:48 AM
Scull (Linux Device Driver) harsh_electro Linux - Newbie 3 11-07-2008 05:39 AM
Scull Device Driver (problems to compile) manuzinhac Linux - Hardware 0 05-19-2005 09:00 AM
Trouble running make to compile example scull device driver taillefer Programming 3 03-23-2004 12:53 AM
scanpci returns fatal error & modem init string? billybob92 Linux - Newbie 1 02-01-2004 02:12 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 05:28 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration