how to write a shell script which communicates with the kernel module - c

Below is my kernel module,which I tested through C program but now instead of using c application I want to write a shell script which do read and write operation with my kernel module ?
Thanks in advance.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define DEVICE_NAME "mydevice"
#define CLASS_NAME "device"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ABC");
MODULE_DESCRIPTION("A simple Linux character driver");
MODULE_VERSION("0.1");
static int majorNumber;
static char message[256] = {0};
static short size_of_message;
static int numberOpens = 0;
static struct class* character_deviceClass = NULL;
static struct device* character_deviceDevice = NULL;
static int dev_open(struct inode *, struct file *);
static int dev_release(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *, size_t, loff_t *);
static ssize_t dev_write(struct file *, const char *, size_t, loff_t *);
static DEFINE_MUTEX(devicedev_mutex);
static struct file_operations fops =
{
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
static int __init character_device_init(void){
printk(KERN_INFO "Shell: Initializing the character device LKM\n");
majorNumber = register_chrdev(0, DEVICE_NAME, &fops);
if (majorNumber<0){
printk(KERN_ALERT "character device failed to register a major number\n");
return majorNumber;
}
printk(KERN_INFO "character device: registered correctly with major number %d\n", majorNumber);
character_deviceClass = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(character_deviceClass)){
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to register device class\n");
return PTR_ERR(character_deviceClass);
}
printk(KERN_INFO "character device: device class registered correctly\n");
character_deviceDevice = device_create(character_deviceClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
if (IS_ERR(character_deviceDevice)){
class_destroy(character_deviceClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to create the device\n");
return PTR_ERR(character_deviceDevice);
}
printk(KERN_INFO "character device: device class created correctly\n");
mutex_init(&devicedev_mutex);
return 0;
}
static void __exit character_device_exit(void){
mutex_destroy(&devicedev_mutex);
device_destroy(character_deviceClass, MKDEV(majorNumber, 0));
class_unregister(character_deviceClass);
class_destroy(character_deviceClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_INFO "character device: Goodbye from the LKM!\n");
}
static int dev_open(struct inode *inodep, struct file *filep){
if(!mutex_trylock(&devicedev_mutex))
{
printk(KERN_ALERT "Character device: Device in use by another process");
return -EBUSY;
}
numberOpens++;
printk(KERN_INFO "character device: Device has been opened %d time(s)\n", numberOpens);
return 0;
}
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset){
int error_count = 0;
error_count = copy_to_user(buffer, message, size_of_message);
if (error_count==0){
printk(KERN_INFO "character device: Sent %d characters to the user\n", size_of_message);
return (size_of_message=0);
}
else {
printk(KERN_INFO "character device: Failed to send %d characters to the user\n", error_count);
return -EFAULT;
}
}
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
sprintf(message, "%s(%d letters)", buffer, len);
size_of_message = strlen(message);
printk(KERN_INFO "character device: Received %d characters from the user\n", len);
return len;
}
static int dev_release(struct inode *inodep, struct file *filep){
mutex_unlock(&devicedev_mutex);
printk(KERN_INFO "character device: Device successfully closed\n");
return 0;
}
module_init(character_device_init);
module_exit(character_device_exit);

Let's say that you registered with major number 254 and minor number 1 (the actual code given in your question logs the allocated numbers to dmesg, so check there). If you didn't have udev or similar configured to create a /dev/mydevice for you, you could do so yourself:
mknod /dev/mydevice c 254 1 # substitute the real allocated values
At that point, opening it is the same as with anything else:
# file descriptor number 3 is arbitrary, but the same number needs to be reused later
# don't use 0-2, which are reserved for stdin/stdout/stderr
exec 3<>/dev/mydevice
...and reads and writes are similarly conventional:
echo "This is a write" >&3
read varname <&3 # read until newline from device

Related

Linux Device Driver -- file operations not working

I have recently updated my kernel and I am no longer able to use a previously written device drivers. My driver's init and exit functions work fine and log a message to the kernel log. However, I am no longer able to write, read, ioctl, open, or release the file. The functions do not print anything into the log file. I am compiling against linux-headers-5.4.79-v7l+.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
MODULE_LICENSE("Dual BSD/GPL");
#define DEVICE_NAME "device"
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static long int device_ioctl(struct file *, unsigned int, unsigned long);
static struct file_operations fops =
{
owner: THIS_MODULE,
read: device_read,
write:device_write,
unlocked_ioctl: device_ioctl,
open: device_open,
release: device_release
};
struct cdev *device_cdev;
dev_t deviceNumbers;
static int init(void)
{
int ret = alloc_chrdev_region(&deviceNumbers, 0, 1, DEVICE_NAME);
if (ret < 0) {
printk(KERN_ALERT "Error registering: %d", ret);
return -1;
}
device_cdev = cdev_alloc();
cdev_init(device_cdev, &fops);
ret = cdev_add(device_cdev, deviceNumbers, 1);
printk(KERN_INFO "Device initialized");
return 0;
}
static void cleanup(void)
{
unregister_chrdev_region(deviceNumbers, 1);
cdev_del(device_cdev);
printk(KERN_INFO "Device unloaded");
}
static int device_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device open");
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device released");
return 0;
}
static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device write");
return 0;
}
static ssize_t device_read(struct file *filp, char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device read");
return 0;
}
static long int device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
printk(KERN_INFO "Device IOCTL");
return 0;
}
module_init(init);
module_exit(cleanup);
You should add terminating "\n" at the end of your prints to force their flush into the kernel log buffer. Here is your module with some enhancement suggestions:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
MODULE_LICENSE("Dual BSD/GPL");
#define DEVICE_NAME "device"
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static long int device_ioctl(struct file *, unsigned int, unsigned long);
static const struct file_operations fops =
{
.owner= THIS_MODULE,
.read= device_read,
.write=device_write,
.unlocked_ioctl= device_ioctl,
.open= device_open,
.release= device_release
};
struct cdev *device_cdev;
dev_t deviceNumbers;
static int __init init(void) // <------ Add __init keyword for kernel cleanups
{
// This returns the major number chosen dynamically in deviceNumbers
int ret = alloc_chrdev_region(&deviceNumbers, 0, 1, DEVICE_NAME);
if (ret < 0) {
printk(KERN_ALERT "Error registering: %d\n", ret);
return -1;
}
device_cdev = cdev_alloc();
cdev_init(device_cdev, &fops);
ret = cdev_add(device_cdev, deviceNumbers, 1);
printk(KERN_INFO "Device initialized (major number is %d)\n", MAJOR(deviceNumbers));
return 0;
}
static void __exit cleanup(void) // <------ Add __exit keyword for kernel cleanups
{
unregister_chrdev_region(deviceNumbers, 1);
cdev_del(device_cdev);
printk(KERN_INFO "Device unloaded\n");
}
static int device_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device open\n");
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device released\n");
return 0;
}
static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device write\n");
return len; // <-------------- To stop the write
}
static ssize_t device_read(struct file *filp, char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device read\n");
return len; // <-------------- To stop the read
}
static long int device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
printk(KERN_INFO "Device IOCTL\n");
return 0;
}
module_init(init);
module_exit(cleanup);
Check the current settings for the kernel log level.
$ cat /proc/sys/kernel/printk
4 4 1 7
In the preceding, the first column specifies that only messages with a log level lower than 4 will be printed.
The values accepted by printk() are:
KERN_EMERG 0 System is unusable
KERN_ALERT 1 Action must be taken immediately
KERN_CRIT 2 Critical conditions
KERN_ERR 3 Error conditions
KERN_WARNING 4 Warning conditions
KERN_NOTICE 5 Normal but significant condition
KERN_INFO 6 Informational
KERN_DEBUG 7 Debug-level messages
So, the KERN_INFO level is 6 which is greater than 4!
We modify the configuration:
$ sudo sh -c "echo 7 4 1 7 > /proc/sys/kernel/printk"
$ cat /proc/sys/kernel/printk
7 4 1 7
I built your module with the suggested modifications and tried it on Linux 5.4.0-58:
$ uname -a
Linux xxxx 5.4.0-58-generic #64-Ubuntu SMP Wed Dec 9 08:16:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ sudo insmod ./device.ko
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
$ lsmod
Module Size Used by
device 16384 0
[...]
$ cat /proc/devices
Character devices:
[...]
235 device
$ sudo mknod /dev/device c 235 0
$ ls -l /dev/device
crw-r--r-- 1 root root 235, 0 janv. 3 10:33 /dev/device
$ sudo sh -c "echo foo > /dev/device"
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
[ 7311.507652] Device open
[ 7311.507672] Device write
[ 7311.507677] Device released
$ sudo rmmod device
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
[ 7311.507652] Device open
[ 7311.507672] Device write
[ 7311.507677] Device released
[ 7361.523964] Device unloaded
$ sudo rm /dev/device

How to resolve reading and writing operations with /dev file as a kernel module in Linux?

Obviuosly, it's a unsuprising newbie's question after a lot of troubles with kernel programming. I try to launch a program that gets driver file in /dev folder available for some reading and writing (indeed, I realize it's rather unsafe idea, but I need strongly going ahead with all that experience). Let's look at a module source code:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
int init_module(void); // driver file initialization as opening it
void cleanup_module(void); // exec files removal ahead of shutting driver file
static int device_open(struct inode *, struct file *); // driver file opening
static int device_release(struct inode *, struct file *); // return of system resource control
static ssize_t device_read(struct file *, char *, size_t, loff_t *); // reading from driver file
static ssize_t device_write(struct file *, const char *, size_t, loff_t *); // writing into driver file
#define SUCCESS 1
#define DEVICE_NAME "sample device"
#define BUF_LEN 80
static int Major; // device's major number
static int Device_Open = 0; // device access counter
static char message[BUF_LEN]; // buffer for both read and write operations
static char *message_ptr;
// list of basic operations executable by driver
static struct file_operations ops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &ops); // major number assignment
// evaluate whether driver file is accessible
if(Major < 0) {
printk(KERN_ALERT "Device registration attempt failed\n");
return Major;
}
return SUCCESS;
}
void cleanup_module(void)
{
unregister_chrdev(Major, DEVICE_NAME); // cancelling driver registration in file system before exit
printk(KERN_ALERT "Driver file of /dev/%s c %d 0 has been destroyed\n", DEVICE_NAME, Major);
return;
}
static int device_open(struct inode * node, struct file * file)
{
printk(KERN_INFO "Trying access /dev/%s c %d 0\n", DEVICE_NAME, Major);
static int counter = 0; // access counter initializing
// file control evaluation
if(Device_Open)
return -EBUSY;
Device_Open++; // increment counter to avert driver's immanent running
sprintf(message, "This sentence displayed %d times\n", counter++);
message_ptr = message;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static int device_release(struct inode * node, struct file * file)
{
printk(KERN_INFO "Trying closure of /dev/%s c %d 0\n", DEVICE_NAME, Major);
Device_Open--; // decrement counter to keep driver file removable as well
module_put(THIS_MODULE);
return SUCCESS;
}
static ssize_t device_read(struct file * file, char * ch, size_t num, loff_t * off)
{
int read_bytes = 0; // output size
printk(KERN_INFO "Trying read from /dev/%s c %d 0\n", DEVICE_NAME, Major);
if(*message_ptr == 0)
return 0;
// loop-executed reading from file
while(num && *message_ptr) {
put_user(*(message_ptr++), ch++);
num--;
read_bytes++;
}
printk("%d bytes read, %d bytes to be handled", read_bytes, num);
return read_bytes;
}
// updated stuff
static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
char message_from_user[BUF_LEN];
if(copy_from_user(message_from_user, buff, len)) return -EINVAL;
printk(KERN_INFO "length of message:%d message:'%s'", (int)len, message_from_user);
return len;
}
To test reading/writing, I use this code:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <linux/unistd.h>
extern int errno;
int main()
{
int fd; // file descriptor id
size_t cnt = 0; // input / output number of bytes
size_t cnt_2 = 0;
char inputBuffer[30] = "Device file is open"; // write operation buffer
char outputBuffer[50]; // read operation buffer
printf("Continuing with basics of Linux drivers...\n");
// evaluate accessibility of driver file
fd = open("/dev/dev", O_RDWR);
if(fd == -1) {
close(fd);
printf("File opening isn't completed\n");
return 1;
}
printf("Driver file is open now\n");
// writing from file
cnt = write(fd, inputBuffer, sizeof(inputBuffer));
printf("Driver got written %d bytes\n", cnt);
// read into file
cnt = read(fd, outputBuffer, sizeof(outputBuffer));
printf("Driver received %d bytes\n", cnt);
int i = 0;
// display an input message
while(i < cnt) {
printf("%c", outputBuffer[i]);
printf("%s", "\n");
i++;
}
close(fd); // wrap up driver connection and clear memory
printf("Driver file is close\n");
return 0;
}
Altough the module was built in as well as dev file was made by mknod (I run it on Ubuntu 18.04), I'm stuck at write operation due to some miscomprehension of driver calls in user/kernel spaces. Once I start my program, outputs are here as follows:
Continuing with basics of Linux drivers...
Driver file is open now
Driver got written -1 bytes
Followed by last line output, the system becomes inoperable (no response until I make off PC). That's a case I think of like a matter of memory control or, most probably, some driver file properties. However, user rights have been granted to reading / writing / executing, no access restrictions are inferable indeed. Hopefully, it's possible to point out to what's wrongness in the code posted here.
Seeing your code you don't handle the writing part.
static ssize_t device_write(struct file * file, const char * ch, size_t num, loff_t * off)
{
printk(KERN_ALERT "Operation denied\n");
return -EINVAL;
}
Thus there is no way your module can possibly work.
But your crash comes from memory accesses in your reading function (check this with strace). I let you understand your issue. dmesg should help (or in the case your system panics you can make the log persistant to debug it after rebooting your system).

insmod: ERROR: Could not insert module : No such device

I'm trying to implement character device driver in C at Linux.
My code is as follows:
#include<linux/device.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/err.h>
#include<asm/uaccess.h>
#define SUCCESS 0
#define DEVICE_NAME "chardev"
#define BUF_LEN 80
MODULE_LICENSE("GPL");
static int Major;
static char msg[BUF_LEN]={0};
static short s_o_msg;
static int Device_Open = 0;
static struct class* chardevClass = NULL;
static struct device* chardevDevice = NULL;
static char *msg_Ptr;
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int __init chardev_init(void){
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
return Major;
}
chardevDevice = device_create(chardevClass, NULL, MKDEV(Major,0), NULL, DEVICE_NAME);
if (IS_ERR(chardevDevice)) {
class_destroy(chardevClass);
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_ALERT
"Failed to create the device\n");
return PTR_ERR(chardevDevice);
}
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "the driver, create a dev file with\n");
printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
printk(KERN_INFO "the device file.\n");
printk(KERN_INFO "Remove the device file and module when done.\n");
return SUCCESS;
}
static void __exit chardev_exit(void){
device_destroy(chardevClass, MKDEV(Major, 0));
class_unregister(chardevClass);
class_destroy(chardevClass);
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_INFO "Goodbye!\n");
}
static int device_open(struct inode *inodep, struct file *filep)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static ssize_t device_read(struct file *filep, char *buffer, size_t length, loff_t * offset){
int bytes_read = 0;
if (*msg_Ptr == 0)
return 0;
while (length && *msg_Ptr) {
put_user(*(msg_Ptr++), buffer++);
length--;
bytes_read++;
}
return bytes_read;
}
static int device_release(struct inode *inodep, struct file *filep)
{
Device_Open--;
module_put(THIS_MODULE);
return 0;
}
static ssize_t device_write(struct file *filep, const char *buffer, size_t length, loff_t *offset){
sprintf(msg, "%s(%zu letters)", buffer, length);
s_o_msg = strlen(msg);
printk(KERN_INFO "Received %zu characters from the user\n", length);
return length;
}
module_init(chardev_init);
module_exit(chardev_exit);
then, I compile this with following command and to this moment everything looks just fine:
obj-m := memory.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
but when I tried to run this module with
sudo /sbin/insmod memory.ko
I get an error :
insmod: ERROR: Could not insert module : No such device
Could you explain me please what I'm doing wrong and what should I do to run this module properly?
Thanks a lot.
You forget to create the class( class_create) before device_create() because if you see
root#achal:/sys/class# ls
.. there are so many different class..
your device also should be in one class that's why create one class using class_create();
Add below line in your code.
chardevClass = class_create(THIS_MODULE, "overflow");
chardevDevice = device_create(chardevClass, NULL, MKDEV(Major,0), NULL, DEVICE_NAME);
root mode is required for inserting a module, Sequence for compiling, inserting and running a module are :
First do make
root#root:~/s_flow# make
then do insmod & analyse dmesg output
root#root:~/s_flow# insmod memory.ko
root#root:~/s_flow# dmesg
..
.. check here whether __init chardev_init() is invoked or not
or you can check modinfo also
root#root:~/s_flow# modifno memory.ko
I hope it helps.

IOCTL call not working with driver

I wrote a IOCTL driver and a corresponding ioctl app with a header file containing commands.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include "myioctl.h"
#include <linux/ioctl.h>
#define NAME MyCharDevice
//Function Prototypes
int NAME_open(struct inode *inode, struct file *filp);
int NAME_release(struct inode *indoe, struct file *filp);
ssize_t NAME_write(struct file *filp, char __user *Ubuff, size_t count, loff_t *offp);
ssize_t NAME_read(struct file *filp, char __user *Ubuff, size_t count, loff_t *offp);
int NAME_flush (struct file *filp);
int NAME_IOCTL (struct inode *inode, struct file *filp, unsigned long cmd, unsigned long val);
//Structure that defines the operations that the driver provides
struct file_operations fops =
{
.owner = THIS_MODULE,
.open = NAME_open,
.read = NAME_read,
.write = NAME_write,
.unlocked_ioctl = NAME_IOCTL,
.release = NAME_release,
.flush = NAME_flush,
};
//Structure for a character driver
struct cdev *my_cdev;
//Init Module
static int __init CharDevice_init(void)
{
int result;
int MAJOR,MINOR;
dev_t Mydev;
Mydev = MKDEV(255,0);//Create a device number
MAJOR=MAJOR(Mydev);
MINOR=MINOR(Mydev);
printk("\nThe Major Number is %d...THe Minor Number is %d\n",MAJOR,MINOR);
result=register_chrdev_region(Mydev,1,"MyCharDevice");//register device region.....
if(result<0)
{
printk(KERN_ALERT "\nThe Region requested for is not obtainable\n");
return(-1);
}
my_cdev = cdev_alloc();//allocate memory to Char Device structure
my_cdev->ops = &fops;//link our file operations to the char device
result=cdev_add(my_cdev,Mydev,1);//Notify the kernel abt the new device
if(result<0)
{
printk(KERN_ALERT "\nThe Char Devide has not been created......\n");
return (-1);
}
return 0;
}
//Cleanup Module
void __exit CharDevice_exit(void)
{
dev_t Mydev;
int MAJOR,MINOR;
Mydev=MKDEV(255,0);
MAJOR=MAJOR(Mydev);
MINOR=MINOR(Mydev);
printk("\nThe Major Number is %d...THe Minor Number is %d\n",MAJOR,MINOR);
unregister_chrdev_region(Mydev,1);//unregister the device numbers and the device created
cdev_del(my_cdev);
printk(KERN_ALERT "\nI have unregistered the stuff that was allocated.....Goodbye for ever.....\n");
return;
}
int NAME_IOCTL (struct inode *inode, struct file *filp, unsigned long cmd, unsigned long val)
{
int BAUD=0, STOP;
char PARITY, CONFIG;
printk ("In IOCTL\n");
printk("command = %d %d val = %d\n", cmd, SET_BAUD, val);
switch (cmd) {
case SET_BAUD:
get_user (BAUD, (int *)val);
printk ("The baud is %d", BAUD);
case SET_PARITY:
case SET_STOP:
case READ_CONFIG:
default:
return -1;
}
return 0;
}
//Open System Call
int NAME_open(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "\nThis is the Kernel....Open Call.....I have nothing to do.....but YOU ALL HAVE....HAHAHAHA...\n");
return 0;
}
//Close System Call
int NAME_release(struct inode *indoe, struct file *filp)
{
printk(KERN_ALERT "\nThis is the release method of my Character Driver......Bye Dudes......\n");
return 0;
}
//Write Functionality
ssize_t NAME_write(struct file *filp, char __user *Ubuff, size_t count, loff_t *offp)
{
char Kbuff[80];
unsigned long result;
ssize_t retval;
//strcpy(Kbuff,Ubuff);
result=copy_from_user((char *)Kbuff,(char *)Ubuff,count); //get user data
if(result==0)
{
printk(KERN_ALERT "\nMessage from the user......\n>>>> %s <<<<\n",Kbuff);
printk(KERN_ALERT "\n Data Successfully Written.....\n");
retval=count;
return retval;
}
else
{
printk(KERN_ALERT "\n Error Writing Data\n");
retval=-EFAULT;
return retval;
}
}
//read Functionality
ssize_t NAME_read(struct file *filp, char __user *Ubuff, size_t count, loff_t *offp)
{
char Kbuff[]="THis is some date from the kernel to the user....User,ENJOY......";
unsigned long result;
ssize_t retval;
//strcpy(Kbuff,Ubuff);
result=copy_to_user((char *)Ubuff,(char *)Kbuff,sizeof(Kbuff)); //copy to user
if(result==0)
{
//printk("\nMessage from the user......\n>>>> %s <<<<\n");
printk(KERN_ALERT "\n Data Successfully read.....\n");
retval=count;
return retval;
}
else
{
printk(KERN_ALERT"\n Error Writing Data to User\n");
retval=-EFAULT;
return retval;
}
}
int NAME_flush (struct file *filp)
{
printk("\n This is the close function of the file....");
return 0;
}
//Module over ride functions
module_init(CharDevice_init);
module_exit(CharDevice_exit);
header file
#define MAGIC 'x'
#define SET_BAUD _IOW(MAGIC,0, int)
#define SET_PARITY _IOW(MAGIC, 1, char)
#define SET_STOP _IOW(MAGIC, 2, int)
#define READ_CONFIG _IOR(MAGIC, 3, int)
c file
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include "myioctl.h"
int main()
{
int FileDesc, Baud=9600;
// char Ubuff[]="THis is the User Buffer......Sending Data to the Kernel....";
// char Kbuff[100];
FileDesc=open("/dev/MyCharDevice",O_RDWR);
if(FileDesc <0)
{
printf("\nError Opening Device\n");
exit(1);
}
ioctl (FileDesc, SET_BAUD, &Baud);
printf("%d %d \n", SET_BAUD, &Baud);
// write(FileDesc,Ubuff,sizeof(Ubuff));
// read(FileDesc,Kbuff,sizeof(Ubuff));
// printf("\n The Data read from the Kernel is\n>>>> %s <<<<\n",Kbuff);
close(FileDesc);
}
I am printing in driver what are the command and value of the argument that print like this
command = 1622004312 1074034688 val = 1622004312
So sent command is equal to the argument I sent. Why this is happening?
I used older IOCTL prototype in my driver.
it should be of this type
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
#else
static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
#endif
In my case against my kernel
static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
is the correct type.

endlessly looping when reading from character device

For a homework assignment, I have written a character device driver. It seems to work OK. I can read and write it. The problem is that when I read the device, it endlessly loops, printing out the contents of the message buffer over and over.
This seems like it should be fairly straight forward. Just use copy_to_user(), but it's proven to be very problematic.
Anyway, here is the code. I think the problem is in the gdev_read() function.
The printk's are there to serve as debugging as well as talking points, since I have to present the project in class.
/*
* Implement a generic character pseudo-device driver
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
/* you need these, or the kernel will be tainted */
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple sample character device driver");
/*
* function prototypes
*/
int init_module(void);
void cleanup_module(void);
static ssize_t gdev_read(struct file *, char *, size_t, loff_t *);
static ssize_t gdev_write(struct file *, const char *, size_t, loff_t *);
static int gdev_open(struct inode *, struct file *);
static int gdev_release(struct inode *, struct file *);
/* macros */
#define TRUE 1
#define FALSE 0
#define MAX_MSG_LEN 64
/*
* global variables
*/
static dev_t dev_num; /* device number, for new device */
static char *mesg; /* buffer for message */
/* file operations structure, so my device knows how to act */
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = gdev_read,
.write = gdev_write,
.open = gdev_open,
.release = gdev_release,
};
/* character device struct. Declaired here, but initialized elsewhere */
struct cdev *gdev;
int init_module(void)
{
int err;
printk(KERN_ALERT "in init_module\n");
if(alloc_chrdev_region(&dev_num, 0, 1, "/dev/gdev")){
printk(KERN_INFO "Could not allocate device numbers\n");
printk(KERN_INFO "Module gdev not loaded\n");
return -1;
}
/* now I need to make the device and register it */
gdev = cdev_alloc();
gdev->owner = THIS_MODULE;
gdev->ops = &fops;
err = cdev_add(gdev, dev_num, 1);
if(err){
printk(KERN_NOTICE "Error %d adding gdev", err);
return err;
}
mesg = (char *)vmalloc(MAX_MSG_LEN);
printk(KERN_INFO "Module gdev successfully loaded.\n");
printk(KERN_INFO "gdev Major Number: %d\n", MAJOR(dev_num));
return 0;
}
void cleanup_module(void)
{
printk(KERN_ALERT "in cleanup_module\n");
unregister_chrdev_region(dev_num, 3);
vfree(mesg);
cdev_del( gdev );
printk(KERN_INFO "Module gdev unregistered\n");
}
static ssize_t gdev_read(struct file *filp, char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN;
printk(KERN_ALERT "in gdev_read\n");
if(copy_to_user(page, mesg, bytes)){
return -EFAULT;
}
return bytes;
}
static ssize_t gdev_write(struct file *filp, const char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN;
printk(KERN_ALERT "in gdev_write\n");
if(copy_from_user(mesg, page, bytes)){
return -EFAULT;
}
return bytes;
}
static int gdev_open(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "in gdev_open\n");
return 0;
}
static int gdev_release(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "in gdev_release\n");
/* doesn't do anything because it doesn't need too */
return 0;
}
If zero is not returned from read() (in your case gdev_read()), the read function will be called again.
To stop this you use the loff_t *offset parameter. Increment it by how many bytes you have read using (*offset) += bytes; after copy_to_user(). Next time read() is called, offset will be what you have incremented it to. Now just check how many bytes you have previously sent, and only send what you still have remaining. Your function should look like this:
static ssize_t gdev_read(struct file *filp, char *page,
size_t len, loff_t *offset)
{
ssize_t bytes = len < (MAX_MSG_LEN-(*offset)) ? len : (MAX_MSG_LEN-(*offset));
printk(KERN_ALERT "in gdev_read\n");
if(copy_to_user(page, mesg, bytes)){
return -EFAULT;
}
(*offset) += bytes;
return bytes;
}
You could use 'simple_read_from_buffer' function from 'linux/fs.h':
static ssize_t gdev_read(struct file *filep, char __user *buff, size_t count, loff_t *offp)
{
return simple_read_from_buffer(buff, count, offp, my_buffer, buffer_len);
}
'my_buffer' and 'buffer_len' are defined in your module.

Resources