Device driver not working - linux

I wrote a small device driver for a "coin" device. I create an entry in /drivers/char/Kconfig
and corresponding Makefile, then selected built-in option in menuconfig. The kernel compiled fine (built-in.o file was created). But I still can't access the device (/dev/coin was not created) and there was no entry under /proc/devices.
Please help!!
I am cross-compiling for powerpc
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/random.h>
#include <linux/debugfs.h>
#include <linux/init.h>
#define DEVNAME "coin"
#define LEN 20
enum values {HEAD, TAIL};
struct dentry *dir, *file;
int file_value;
int stats[2] = {0, 0};
char *msg[2] = {"head\n", "tail\n"};
static int major;
static struct class *class_coin;
static struct device *dev_coin;
static ssize_t r_coin(struct file *f, char __user *b,
size_t cnt, loff_t *lf)
{
char *ret;
u32 value = random32() % 2;
ret = msg[value];
stats[value]++;
return simple_read_from_buffer(b, cnt,
lf, ret,
strlen(ret));
}
static struct file_operations fops = { .read = r_coin };
#ifdef CONFIG_COIN_STAT
static ssize_t r_stat(struct file *f, char __user *b,
size_t cnt, loff_t *lf)
{
char buf[LEN];
snprintf(buf, LEN, "head=%d tail=%d\n",
stats[HEAD], stats[TAIL]);
return simple_read_from_buffer(b, cnt,
lf, buf,
strlen(buf));
}
static struct file_operations fstat = { .read = r_stat };
#endif
static int __init coin_init(void)
{
void *ptr_err;
major = register_chrdev(0, DEVNAME, &fops);
if (major < 0)
return major;
class_coin = class_create(THIS_MODULE,
DEVNAME);
if (IS_ERR(class_coin)) {
ptr_err = class_coin;
goto err_class;
}
dev_coin = device_create(class_coin, NULL,
MKDEV(major, 0),
NULL, DEVNAME);
if (IS_ERR(dev_coin))
goto err_dev;
#ifdef CONFIG_COIN_STAT
dir = debugfs_create_dir("coin", NULL);
file = debugfs_create_file("stats", 0644,
dir, &file_value,
&fstat);
#endif
return 0;
err_dev:
ptr_err = class_coin;
class_destroy(class_coin);
err_class:
unregister_chrdev(major, DEVNAME);
return PTR_ERR(ptr_err);
}
static void __exit coin_exit(void)
{
#ifdef CONFIG_COIN_STAT
debugfs_remove(file);
debugfs_remove(dir);
#endif
device_destroy(class_coin, MKDEV(major, 0));
class_destroy(class_coin);
return unregister_chrdev(major, DEVNAME);
}
module_init(coin_init);
module_exit(coin_exit);

What if you manually insert module into kernel using insmod? Does it work? Any messages in dmesg?
As I remember entries in /dev (/dev/coin) should be created manually using mknod, but you need major number of registered device. Just printk it after register_chrdev().

Related

Why this kernel module does not handle open and read syscall?

I'm learning about Linux kernel module with Ubuntu 20.04 (Linux kernel 5.4.0-37 generic). The following is the code that actual code.
I have expected to following module to that pass single byte random number between 0-255 (get_random_bytes(&c, 1)) to user space buffer when it handle ->read() syscall then print a message to dmesg.
But Unfortunately, for now, it does not work. It seems like does not add handle of ->read() and ->open() syscalls.
Why it does not handle ->read() and ->open() syscall?
User space applicattion code (open and read device file) app.c:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main() {
char c[8];
memset(c, '\0', 8);
int fd = open("/dev/devsaikoro0", O_RDONLY);
read(fd, &c, 1);
//printf("Hello\n");
printf("%s\n", c);
}
Kernel module code:
#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/random.h>
MODULE_LICENSE("Dual BSD/GPL");
static int devsaikoro_num = 3;
static int devsaikoro_major = 0;
static int devsaikoro_minor = 0;
static struct cdev devsaikoro_cdev;
static struct class *devsaikoro_class = NULL;
static dev_t saikoro_dev;
ssize_t read_num(struct file * filp, char __user *buf, size_t count, loff_t *f_pos)
{
int retval;
char c;
get_random_bytes(&c, 1);
if (copy_to_user(buf, &c, 1)) {
printk("devsaikoro read failed\n");
retval = -EFAULT;
return retval;
} else {
printk("devsaikoro read succeeded\n");
return 1;
}
}
struct file_operations fops = {
.read = read_num,
};
int saikoro_open(struct inode *inode, struct file *file) {
printk("devsaikoro open\n");
file->f_op = &fops;
return 0;
}
struct file_operations fops2 = {
.open = saikoro_open,
};
static int devsaikoro_init(void)
{
dev_t dev = MKDEV(devsaikoro_major, 0);
int alloc_ret = 0;
int major;
int cdev_err = 0;
struct device *class_dev = NULL;
alloc_ret = alloc_chrdev_region(&dev, 0, devsaikoro_num, "devsaikoro");
if (alloc_ret) {
goto error;
}
devsaikoro_major = major = MAJOR(dev);
cdev_init(&devsaikoro_cdev, &fops2);
devsaikoro_cdev.owner = THIS_MODULE;
cdev_err = cdev_add(&devsaikoro_cdev, MKDEV(devsaikoro_major, 0), devsaikoro_num);
if (cdev_err)
goto error;
devsaikoro_class = class_create(THIS_MODULE, "devsaikoro");
if (IS_ERR(devsaikoro_class))
goto error;
saikoro_dev = MKDEV(devsaikoro_major, devsaikoro_minor);
class_dev = device_create(devsaikoro_class, NULL, saikoro_dev, NULL, "devsaikoro%d", devsaikoro_minor);
printk(KERN_ALERT "devsaikoro_driver (major %d) installed\n", major);
return 0;
error:
if (cdev_err == 0) {
cdev_del(&devsaikoro_cdev);
}
if (alloc_ret == 0) {
unregister_chrdev_region(dev, devsaikoro_num);
}
return -1;
}
static void devsaikoro_exit(void)
{
dev_t dev = MKDEV(devsaikoro_major, 0);
device_destroy(devsaikoro_class, saikoro_dev);
class_destroy(devsaikoro_class);
cdev_del(&devsaikoro_cdev);
unregister_chrdev_region(dev, devsaikoro_num);
printk(KERN_ALERT "devsaikoro driver removed\n");
}
module_init(devsaikoro_init);
module_exit(devsaikoro_exit);

How to allocate buffer memory at physical address in linux?

I am trying to create a char device driver which can write a buffer at specific physical address(e.g.0x1000-0000). Can someone please help.
Here is a sample of the driver program which I have written.
//include files
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
//device name
#define test_NAME "test"
//need to store this memory at a physical location
static char device_memory[100];
//open function
int test_open (struct inode *my_inode, struct file *my_file)
{
printk(KERN_INFO "Inside the test_open function...\n");
return 0;
}
//close device function
int test_close (struct inode *my_inode, struct file *my_file)
{
printk(KERN_INFO "Inside the test_close function...\n");
return 0;
}
//read function
ssize_t test_read (struct file *my_file, char __user *userbuff, size_t
nRead, loff_t *nReadOffset)
{
int notCopied;
notCopied = copy_to_user(userbuff, device_memory, nRead);
printk("Inside the test_read function...\n");
return (nRead - notCopied);
}
//write function
ssize_t test_write (struct file *my_file, const char __user *userbuff,
size_t nWrite, loff_t *nWriteOffset)
{
int notCopied;
notCopied = copy_from_user(device_memory, userbuff, nWrite);
printk("Inside the test_write function...\n");
return (nWrite - notCopied);
}
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = test_open,
.release = test_close,
.read = test_read,
.write = test_write,
};
int init_module(void)
{
int retval;
retval = register_chrdev(120, test_NAME, &test_fops);
if (retval != 0)
{
printk(KERN_INFO "Failed to register test driver...\n");
return -1;
}
printk(KERN_INFO "test registration succeeded...\n");
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(120, test_NAME);
printk(KERN_INFO "test unregistered successfully...\n");
return;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SK110");
MODULE_DESCRIPTION("Driver for a test (virtual) device.");

Linux driver polling?

I'm starting to learn Linux driver development. I am trying to create a simple driver that polls a function which in the end will read a hardware register at a constant rate (i.e. 10 times a second) and adds the hardware output to a queue which can then be accessed by procfs.
First things first. I need to be able to poll at a consistent rate. I have been reading this online a lot and it seems very simple (my code below). However, when I insmod my module, it doesn't seem to poll at all!!
Can someone please help me understand this and help me figure out what I need to do to make it poll?
I really appreciate you guys' help!
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/poll.h>
MODULE_LICENSE("Dual BSD/GPL");
int silly_open(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "open\n");
return 0;
}
int silly_release(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "release\n");
return 0;
}
ssize_t silly_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
printk(KERN_ALERT "read\n");
return 0;
}
ssize_t silly_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
printk(KERN_ALERT "write\n");
return 0;
}
unsigned int silly_poll(struct file *filp, poll_table *wait)
{
printk(KERN_ALERT "poll\n");
return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
}
struct file_operations silly_fops = {
.read = silly_read,
.write = silly_write,
.poll = silly_poll,
.open = silly_open,
.release = silly_release,
.owner = THIS_MODULE
};
int silly_init(void)
{ printk(KERN_ALERT "init\n");
return 0;
}
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
In hello_init(), you don't connect silly_fops to it. It cannot work automatically if there is no any connection between them.
In order to connect, you probably need to initialize a device with silly_fops(), refer to ch3.4 of ldd3 at http://www.makelinux.net/ldd3/, hope this works.

Miscellaneous Device Driver: Unable to open the device with open() system call

I am trying to implement a system call interception for sys_open() call via kernel module and for that I have defined a miscellaneous device driver MyDevice which can be inserted as kernel module. Below is the code for my kernel module:
#include <linux/version.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/highmem.h>
#include <asm/unistd.h>
MODULE_LICENSE("GPL");
// IOCTL commands
#define IOCTL_PATCH_TABLE 0x00000001
#define IOCTL_FIX_TABLE 0x00000004
//Global variables
int in_use = 0; //set to 1 in open handler and reset to zero in release handler
int is_set = 0; // flag to detect system call interception
unsigned long *sys_call_table = (unsigned long*)0xffffffff81801400; //hard coded address of sys_call_table from /boot/System.map
//function pointer to original sys_open
asmlinkage int (*real_open)(const char* __user, int, int);
//Replacement of original call with modified system call
asmlinkage int custom_open(const char* __user file_name, int flags, int mode)
{
printk("interceptor: open(\"%s\", %X, %X)\n", file_name,flags,mode);
return real_open(file_name,flags,mode);
}
/*
Make the memory page writable
This is little risky as directly arch level protection bit is changed
*/
int make_rw(unsigned long address)
{
unsigned int level;
pte_t *pte = lookup_address(address, &level);
if(pte->pte &~ _PAGE_RW)
pte->pte |= _PAGE_RW;
return 0;
}
/* Make the page write protected */
int make_ro(unsigned long address)
{
unsigned int level;
pte_t *pte = lookup_address(address, &level);
pte->pte = pte->pte &~ _PAGE_RW;
return 0;
}
/* This function will be invoked each time a user process attempts
to open my device. You should keep in mind that the prototype
of this function may change along different kernel versions. */
static int my_open(struct inode *inode, struct file *file)
{
/*Do not allow multiple processes to open this device*/
if(in_use)
return -EBUSY;
in_use++;
printk("MyDevice opened\n");
return 0;
}
/* This function, in turn, will be called when a process closes our device */
static int my_release(struct inode *inode, struct file *file)
{
in_use--;
printk("MyDevice closed\n");
return 0;
}
/*This static function handles ioctl calls performed on MyDevice*/
static int my_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int retval = 0;
switch(cmd)
{
case IOCTL_PATCH_TABLE:
make_rw((unsigned long)sys_call_table);
real_open = (void*)*(sys_call_table + __NR_open);
*(sys_call_table + __NR_open) = (unsigned long)custom_open;
make_ro((unsigned long)sys_call_table);
is_set=1;
break;
case IOCTL_FIX_TABLE:
make_rw((unsigned long)sys_call_table);
*(sys_call_table + __NR_open) = (unsigned long)real_open;
make_ro((unsigned long)sys_call_table);
is_set=0;
break;
default:
printk("sys_open not executed\n");
break;
}
return retval;
}
//populate data struct for file operations
static const struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = &my_open,
.release = &my_release,
.unlocked_ioctl = (void*)&my_ioctl,
.compat_ioctl = (void*)&my_ioctl
};
//populate miscdevice data structure
static struct miscdevice my_device = {
MISC_DYNAMIC_MINOR,
"MyDevice",
&my_fops
};
static int __init init_my_module(void)
{
int retval;
printk(KERN_INFO "Inside kernel space\n");
retval = misc_register(&my_device);
return retval;
}
static void __exit cleanup_my_module(void)
{
if (is_set)
{
make_rw((unsigned long)sys_call_table);
*(sys_call_table + __NR_open) = (unsigned long)real_open;
make_ro((unsigned long)sys_call_table);
}
misc_deregister(&my_device);
printk(KERN_INFO "Exiting kernel space\n");
return;
}
module_init(init_my_module);
module_exit(cleanup_my_module);
The code for my test file is as follows:
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* Define ioctl commands */
#define IOCTL_PATCH_TABLE 0x00000001
#define IOCTL_FIX_TABLE 0x00000004
int main(void)
{
int device = open("/dev/MyDevice", O_RDWR);
printf("%d\n",device);
ioctl(device, IOCTL_PATCH_TABLE);
sleep(2);
ioctl(device, IOCTL_FIX_TABLE);
close(device);
return 0;
}
The problem is that in my test file open("/dev/MyDevice", O_RDWR); is always returning -1, why is it so ? Where am I going wrong ? I checked with ls -l /dev/MyDevice, MyDevice has been successfully registered with following details: crw------- 1 root root 10, 56 Dec 9 19:33 /dev/MyDevice
Sorry, seriously stupid mistake, that's what happens when rookies do things. I just needed to grant the read and write permissions for my miscellaneous char device driver.
sudo chmod a+r+w /dev/MyDevice

fseek char linux device

I'm trying to write a simple char device for linux, I need to read and write the device by fread/fwrite and use fopen and fseek. I've written a simple test program to use my device and I've noted that fpos in fseek function doesn't work and unknow fread after fseek appears. I cannot get the device working because fseek doesn't get a correct file position when opened in r+ mode, everything works except fread if I use file opened in w mode instead.
Thanks folks
/* Makefile */
obj-m += char.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
/* char device char.c */
// to complie:
// # make
// # insmod char.ko
// # dmesg
// (to get majornumber)
// # mknod /dev/dp0 c majornumber 0
// # ./test
// # dmesg
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
int char_init (void);
void char_exit (void);
int char_open (struct inode *, struct file *);
int char_release (struct inode *, struct file *);
ssize_t char_read (struct file *, char __user *, size_t, loff_t *);
ssize_t char_write (struct file *, const char __user *, size_t, loff_t *);
loff_t char_llseek (struct file *, loff_t, int);
int char_open (struct inode *inode, struct file *fp)
{
printk ("f_mode=%d f_pos=%d\n", (int) fp->f_mode, (int)fp->f_pos);
return 0;
}
int char_release (struct inode *inode, struct file *fp)
{
return 0;
}
ssize_t char_read (struct file *fp, char __user *buff, size_t count, loff_t *fpos)
{
printk ("char_read() fp->f_pos=%d\n", (int) fp->f_pos);
return count;
}
ssize_t char_write (struct file *fp, const char __user *buff, size_t count, loff_t *fpos)
{
printk ("char_write() fp->f_pos=%d\n", (int) fp->f_pos);
return count;
}
loff_t char_llseek (struct file *fp, loff_t fpos, int whe)
{
printk ("char_llseek() fpos=%d\n ", (int) fpos);
fp->f_pos = fpos;
return fpos;
}
struct file_operations char_fops =
{
.owner = THIS_MODULE,
.open = char_open,
.release = char_release,
.read = char_read,
.write = char_write,
.llseek = char_llseek,
.ioctl = NULL,
};
/* the char device */
struct cdev cdev;
int char_init ()
{
dev_t mm;
int mj, mi, ret;
mi = 0;
ret = alloc_chrdev_region (&mm, mi, 1, "dp0");
mj = MAJOR(mm);
cdev_init (&cdev, &char_fops);
ret = cdev_add (&cdev, mm, 1);
if (ret<0)
{
printk ("char: unable to add device\n");
return -1;
}
printk ("char: device added major=%d\n", mj);
return 0;
}
void char_exit ()
{
cdev_del(&cdev);
printk ("char: device deleted\n");
}
module_init(char_init);
module_exit(char_exit);
/* test program test.c */
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[])
{
int ret;
FILE *fp;
fp = fopen ("/dev/dp0", "r+");
if (fp == NULL)
{
printf ("open failed\n");
return -1;
}
int x;
x= fseek (fp, 1, SEEK_SET);
printf("ret fseek=%d\n", x);
fseek (fp, 1, SEEK_SET);
fwrite ("\0", 1, 1, fp);
fseek (fp, 2, SEEK_SET);
fread (&ret, 1, 1, fp);
printf ("DONE\n");
fclose (fp);
return 0;
}
// this is my dmesg:
f_mode=31 f_pos=0 // this is my fopen
char_llseek() fpos=0 // this is my first fseek but why fpos=0? it should be 1
char_read() fp->f_pos=0 // what's that?
char_llseek() fpos=0 //this is my second fseek but why fpos is 0 again?
char_read() fp->f_pos=0 // I suppose this is my fread fpos=0?
char_llseek() fpos=-4095 // what's that?
char_llseek() fpos=-4095 // What's that too?
char_llseek() fpos=-4095 // What's that too?
You are using stdio (fread, fseek, etc.) which generally has a buffer of sorts. It may not necessarily translate directly to the syscalls, hence the "unexpected" reads and seeks.

Resources