Skip to content
Advertisement

Writing into a device file prints “Invalid argument”

I am currently working on a device driver where I want to write a sentence to that driver and display it in the kernel. Reading an internal buffer and calling the driver with cat works perfectly fine. However, if I try to write to the device driver it returns the following message: enter image description here

I have the following code for my device driver. I can’t seem to find where I went wrong in my write function…

#include "device_file.h"
#include <linux/fs.h>       /* file stuff */
#include <linux/kernel.h>   /* printk() */
#include <linux/errno.h>    /* error codes */
#include <linux/module.h>   /* THIS_MODULE */
#include <linux/cdev.h>     /* char device stuff */
#include <linux/uaccess.h>  /* copy_to_user() */

static const char g_s_Hello_World_string[] = "Hello from Job & Arief!n";
static const ssize_t g_s_Hello_World_size = sizeof(g_s_Hello_World_string);
static char memory_buffer[500];

/*===============================================================================================*/
static ssize_t device_file_read(struct file *file_ptr, char __user *user_buffer, size_t count, loff_t *possition){

    printk( KERN_NOTICE "Kurniawan_Meulenbeld-driver: Device file is read at offset = %i, read bytes count = %un"
    , (int)*possition
    , (unsigned int)count );

    if( *possition >= g_s_Hello_World_size )
    return 0;

    if( *possition + count > g_s_Hello_World_size )
    count = g_s_Hello_World_size - *possition;

    if( copy_to_user(user_buffer, g_s_Hello_World_string + *possition, count) != 0 )
    return -EFAULT;

    *possition += count;
    return count;
}

/*===============================================================================================*/
static ssize_t memory_write( struct file *filp, const char *buf, size_t count, loff_t *f_pos) {
    const char *tmp;
    tmp=buf+count-1;

    if( copy_from_user(memory_buffer,tmp,1) != 0 )
        return -EFAULT;

    return count;
}
/*===============================================================================================*/
static struct file_operations Kurniawan_Meulenbeld_driver_fops =
        {
                .owner = THIS_MODULE,
                .read = device_file_read,
                .write =  memory_write,
        };

static int device_file_major_number = 0;
static const char device_name[] = "Kurniawan_Meulenbeld-driver";

/*===============================================================================================*/
int register_device(void)
{
    int result = 0;

    printk( KERN_NOTICE "Kurniawan_Meulenbeld-driver: register_device() is called.n" );

    result = register_chrdev( 0, device_name, &Kurniawan_Meulenbeld_driver_fops );
    if( result < 0 )
    {
        printk( KERN_WARNING "Kurniawan_Meulenbeld-driver:  can't register character device with errorcode = %in", result );
        return result;
    }

    device_file_major_number = result;
    printk( KERN_NOTICE "Kurniawan_Meulenbeld-driver: registered character device with major number = %i and minor numbers 0...255n"
            , device_file_major_number );

    return 0;
}

/*===============================================================================================*/
void unregister_device(void)
{
    printk( KERN_NOTICE "Kurniawan_Meulenbeld-driver: unregister_device() is calledn" );
    if(device_file_major_number != 0)
    {
        unregister_chrdev(device_file_major_number, device_name);
    }
}

Advertisement

Answer

Note that redirection >/dev/my-driver is done by the shell under the current user before sudo is invoked. EINVAL from write means fd is attached to an object which is unsuitable for writing.

It is not clear whether hello is a file or a string. cat expects it to be a file.

To write string hello into your device try:

echo "hello" | sudo tee /dev/my-driver

To write file hello into your device try:

cat hello | sudo tee /dev/my-driver
# or
sudo tee /dev/my-driver <hello
Advertisement