Write timer in Linux device driver - c

I'm newbies with the module linux.
I try to create a counter module where the counter is increment on timer callback.
The result of the counter must be send to an other module (a memory module).
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <asm/system.h>
#include <asm/uaccess.h>
MODULE_AUTHOR("Helene");
MODULE_DESCRIPTION("Module memory");
MODULE_SUPPORTED_DEVICE("none");
MODULE_LICENSE("Dual BSD/GPL");
/* Global variables of the driver */
/* Buffer to store data */
char *memory_buffer;
int result;
struct file_operations memory_fops;
int memory_open(struct inode *inode, struct file *filp) {
// printk(KERN_DEBUG "Opening memory module\n");
return 0;
}
int memory_release(struct inode *inode, struct file *filp) {
// printk(KERN_DEBUG "Releasing of memory module\n");
return 0;
}
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos){
// printk(KERN_DEBUG "Reading memory module : %s\n", buf);
if (*f_pos > 0)
return 0;
if (count > strlen(memory_buffer))
count = strlen(memory_buffer);
copy_to_user(buf,memory_buffer,count);
*f_pos = *f_pos + count;
return count;
}
ssize_t memory_write( struct file *filp, const char *buf, size_t count, loff_t *f_pos) {
// printk(KERN_DEBUG "Writing memory module : %s\n", buf);
copy_from_user(memory_buffer, buf, count);
return count;
}
static int __init memory_init(void) {
/* Registering device */
result = register_chrdev(0, "memory", &memory_fops);
if (result < 0) {
printk(KERN_DEBUG "memory: cannot obtain major number \n");
return result;
}
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 1);
printk(KERN_ALERT "Inserting memory module : %d\n", result);
return 0;
fail:
//memory_exit();
return result;
}
static void __exit memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(result, "memory");
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk(KERN_DEBUG "Removing memory module\n");
}
struct file_operations memory_fops = {
owner: THIS_MODULE,
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
module_init(memory_init);
module_exit(memory_exit);
The memory module works. My problem is when I call the function : filp_open/fp->f_op->write/filp_close on the function timer callback.
I have test these functions out of the timer callback and it's work.
Why the filp_open function (& co) don't work on timer callback function ?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
MODULE_LICENSE("GPL");
static struct timer_list my_timer;
int cptNbClic ;
int result;
struct file_operations timer_fops;
int write_file_system(struct file *fp, char * buf){
int nb;
mm_segment_t old_fs=get_fs();
set_fs(get_ds());
nb = fp->f_op->write(fp,buf ,10, &fp->f_pos);
set_fs(old_fs);
return nb;
}
void writeInMemory(void){
// printk(KERN_DEBUG "busy %d\n", busy);
int nbwrite;
char buf[3];
int fmemory;
fmemory=filp_open ("/dev/memory", O_WRONLY | O_APPEND | O_CREAT,0); //don't work on this function
if (fmemory==NULL){//verification de l'ouverture
printk(KERN_ALERT "filp_open error input memory!!.\n");
return -1;
}
sprintf(buf, "%d", cptNbClic);
printk(KERN_DEBUG "%d\n", cptNbClic);
nbwrite = write_file_system(fmemory, buf);
filp_close(fmemory, 0);
}
void my_timer_callback( unsigned long data )
{
cptNbClic++;
printk(KERN_DEBUG "cptNbClic %d\n", cptNbClic);
writeInMemory();
setup_timer(&my_timer, my_timer_callback, 0);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
}
static int timer_open(struct inode *inode, struct file *filp) {
/* setup your timer to call my_timer_callback */
cptNbClic = 0;
setup_timer(&my_timer, my_timer_callback, 0);
/* setup timer interval to 200 msecs */
mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
return 0;
}
static int timer_release(struct inode *inode, struct file *filp) {
/* Success */
printk(KERN_DEBUG "Releasing of cpt module\n");
del_timer(&my_timer);
return 0;
}
static int __init timer_init(void) {
/* Registering device */
result = register_chrdev(0, "timer", &timer_fops);
if (result < 0) {
printk(KERN_DEBUG "timer: cannot obtain major number \n");
return result;
}
printk(KERN_ALERT "Inserting timer module : %d\n", result);
return 0;
}
static void __exit timer_exit(void) {
unregister_chrdev(result, "timer");
printk(KERN_DEBUG "Removing timer module\n");
}
struct file_operations timer_fops = {
owner: THIS_MODULE,
open: timer_open,
release: timer_release
};
/* Declaration of the init and exit functions */
module_init(timer_init);
module_exit(timer_exit);
Sorry for my bad english

No need to call setup_timer function in your my_timer_callback().Already timer is setup. If you want a recurring timer then just again call mod_timer() in your handler which will updates your timer expire value and your timer happily runs again and again till del_timer() call.

Related

my machine crashes after inserting the following kernel module

I am a total beginner in kernel module programming. I wanted to create a module which reads input from the proc filesystem. With this you should be able to perform operations in the program. I did that with threading. However my machine crashes after inserting the module. Probably I did something wrong. Here is the source code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/string.h>
#define PROCFS_MAX_SIZE 1024
#define PROCFS_NAME "test"
MODULE_LICENSE("GPL");
int pid = 1;
static struct proc_dir_entry *Our_Proc_File;
static char procfs_buffer[PROCFS_MAX_SIZE];
static unsigned long procfs_buffer_size = 0;
struct task_struct *task;
static ssize_t procfile_read(struct file *file, char *buffer, size_t buffer_length, loff_t *offset) {
static int flag = 0;
if(flag) {
printk(KERN_INFO "read : END\n");
flag = 0;
return 0;
}
printk(KERN_INFO "read (/proc/%s) : called\n",PROCFS_NAME);
flag = 1;
return snprintf(buffer, buffer_lengh, procfs_buffer);
}
static ssize_t procfile_write(struct file *file,const char *buffer, size_t count, loff_t *offset) {
procfs_buffer_size = count;
if (copy_from_user(procfs_buffer, buffer, procfs_buffer_size)) {
return -EFAULT;
}
return procfs_buffer_size;
}
static int main_prog(void *data) {
int end = 0;
while(!end) {
while(memcmp(procfs_buffer,"\x00",1)==0);
if(memcmp(procfs_buffer,"test",4)) {
printk(KERN_INFO "Test triggered!\n");
}
if(memcmp(procfs_buffer,"exit",4)) {
end++;
}
memset(procfs_buffer, 0, 1024);
}
kthread_stop(task);
}
static struct file_operations fops_struct = {
.read = procfile_read,
.write = procfile_write,
};
int init_module() {
Our_Proc_File = proc_create(PROCFS_NAME, 0666, NULL, &fops_struct);
if (Our_Proc_File == NULL) {
remove_proc_entry(PROCFS_NAME, NULL);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROCFS_NAME);
return -ENOMEM;
}
task = kthread_run(&main_prog, NULL, "thread");
wake_up_process(task);
printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME);
return 0;
}
void cleanup_module() {
remove_proc_entry(PROCFS_NAME, NULL);
printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME);
}
Can someone help me?

How to send signal from Linux kernel space to user space in order to notify about an input hardware event

My kernel module code needs to send signal to a user land program, to transfer its execution to registered signal handler.
In fact, I have developed a C program for my embedded board which make LED turns on and off when I push BUTTON ( the input event ). On the other hand, I have just developed a simple Linux module with its basic functions ( OPEN, CLOSE, READ, WRITE ).
I just don't have any idea how to modify my principal program and my kernel module in order to arrive to my objective.
I share with you my user space program :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
#define BTN_FILE_PATH "/dev/input/event0"
#define LED_PATH "/sys/class/leds"
#define green "green"
void change_led_state(char *led_path, int led_value)
{
char lpath[64];
FILE *led_fd;
strncpy(lpath, led_path, sizeof(lpath) - 1);
lpath[sizeof(lpath) - 1] = '\0';
led_fd = fopen(lpath, "w");
if (led_fd == NULL) {
fprintf(stderr, "simplekey: unable to access led\n");
return;
}
fprintf(led_fd, "%d\n", led_value);
fclose(led_fd);
}
void reset_leds(void)
{
change_led_state(LED_PATH "/" green "/brightness", 0);
}
int configure_leds(void)
{
FILE *r_fd;
char *none_str = "none";
/* Configure leds for hand control */
r_fd = fopen(LED_PATH "/" green "/trigger", "w");
fprintf(r_fd, "%s\n", none_str);
fclose(r_fd);
/* Switch off leds */
reset_leds();
return 0;
}
void eval_keycode(int code)
{
static int green_state = 0;
switch (code) {
case 260:
printf("BTN left pressed\n");
/* figure out green state */
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
}
}
int main(void)
{
int file;
/* how many bytes were read */
size_t rb;
int ret;
int yalv;
/* the events (up to 64 at once) */
struct input_event ev[64];
char *str = BTN_FILE_PATH;
printf("Starting simplekey app\n");
ret = configure_leds();
if (ret < 0)
exit(1);
printf("File Path: %s\n", str);
if((file = open(str, O_RDONLY)) < 0) {
perror("simplekey: File can not open");
exit(1);
}
for (;;) {
/* Blocking read */
rb= read(file, &ev, sizeof(ev));
if (rb < (int) sizeof(struct input_event)) {
perror("simplekey: short read");
exit(1);
}
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++) {
if (ev[yalv].type == EV_KEY) {
printf("%ld.%06ld ",
ev[yalv].time.tv_sec,
ev[yalv].time.tv_usec);
printf("type %d code %d value %d\n",
ev[yalv].type,
ev[yalv].code, ev[yalv].value);
/* Change state on button pressed */
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
}
close(file);
And this is the basic kernel module :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gaston");
MODULE_DESCRIPTION("A simple Linux char driver");
MODULE_VERSION("0.1");
ssize_t exer_open(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device has been opened\n");
return 0;
}
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_close(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device successfully closed\n");
return 0;
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
};
int exer_simple_module_init(void) {
printk(KERN_INFO "Initializing the LKM\n");
register_chrdev(240, "Simple Char Drv", &exer_file_operations);
return 0;
}
void exer_simple_module_exit(void) {
unregister_chrdev(240, "Simple Char Drv");
}
module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);
I hope you will help me. Thank you!
I will concentrate on sending a signal, since that is what you asked for, although sending signals to a process is quite brutal. It would be better to implement poll and read file operations so the user code can wait for events from the device and read them.
Anyway, for sending a signal to the processes that opened the device, the things you need are:
You need a struct fasync_struct * in the private data of your device:
struct fasync_struct *pasync_queue;
It needs to be initialized to NULL by some means during initialization of your device private data. How you do that is up to you.
You need a fasync file operation handler pointed to by the fasync member of your struct file_operations. The implementation of the fasync handler is very simple as it just needs to call fasync_helper() using supplied parameters and a pointer to your device's private struct fasync_struct *:
static int exer_fasync(int fd, struct file *pfile, int mode)
{
// N.B. Change this code to use the pasync_queue member from your device private data.
struct fasync_struct **fapp = &pasync_queue;
return fasync_helper(fd, pfile, mode, fapp);
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
.fasync = exer_fasync,
};
Your device driver can send a SIGIO signal by calling kill_fasync() as follows:
// N.B. Change this code to use the pasync_queue member from your device private data.
struct fasync_struct **fapp = &pasync_queue;
kill_fasync(fapp, SIGIO, POLL_IN);
N.B. The last parameter (value POLL_IN in this case) affects the value of the si_band member of the siginfo_t that your application sees in its signal handler.
Your application needs to set a signal handler for the SIGIO signal. I recommend usingsigaction() to set this up.
Your application needs to set the O_ASYNC flag when it opens the device file, or set it by calling fcntl(fd, F_SETFL, O_ASYNC); after opening the device file.

Correct way to initialize semaphore in linux driver

I wrote this linux char driver just to control open call,
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>
#include <linux/device.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
#define CLASS_NAME "myclass"
#define MINOR_NUM 0
#define MINOR_CNT 1
static struct class *myclass=NULL;
static struct device *mydevice=NULL;
static dev_t mycdevt;
static struct cdev *mycdev;
static struct semaphore *sem;
static int myopen(struct inode *inod, struct file *fp)
{
down(sem);
printk(KERN_INFO "critical section\n");
return 0;
}
static int myclose(struct inode *inod, struct file *fp )
{
up(sem);
printk(KERN_INFO "critical section freed\n");
return 0;
}
static ssize_t myread(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static ssize_t mywrite(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static struct file_operations fops =
{
.open = myopen,
.release = myclose,
.read = myread,
.write = mywrite,
};
static int __init myinit(void)
{
int ret;
ret = alloc_chrdev_region ( &mycdevt, MINOR_NUM, MINOR_CNT, "mycdevt");
if(ret<0)
{
printk(KERN_INFO "chardev can't be allocated\n");
// goto label;//todo
}
mycdev = cdev_alloc();//instead of cdev_alloc, we can use cdev_init(&mycdev, &fops);
if(mycdev == NULL)
{
printk(KERN_INFO"cdev_alloc failed\n");
// goto label;//todo
}
mycdev->ops = &fops;
ret = cdev_add(mycdev, mycdevt, 1);
if(ret < 0)
{
printk(KERN_INFO"cdev_add failed\n");
// goto label;//todo
}
myclass = class_create(THIS_MODULE, CLASS_NAME);
if(myclass == NULL)
{
printk(KERN_INFO"class create failed\n");
// goto label;//todo
}
mydevice = device_create(myclass, NULL, mycdevt, NULL, "mydevice");
if(mydevice == NULL)
{
printk(KERN_INFO"device create failed\n");
// goto label;//todo
}
sema_init(sem, 1);//here is the problem
printk(KERN_INFO"myinit done\n");
return 0;
}
static void __exit myexit(void)
{
device_destroy(myclass, mycdevt);
class_unregister(myclass);
class_destroy(myclass);
cdev_del(mycdev);
unregister_chrdev(MAJOR(mycdevt), "mycdevt");
printk(KERN_INFO "exited\n");
}
module_init(myinit);
module_exit(myexit);
I am following ldd3 book, and tried to use simple APIs to use semahore for an app.
What happened is my kernel crashed when it called sema_init function. I read that semaphore is used in mutex mode
http://www.makelinux.net/ldd3/chp-5-sect-3
I also read that semaphore is not a mutex as there is no ownership. I have yet to explore that 'ownership' thing, but for now I am not able to make a simple semaphore.
What wrong I am doing here?
There's no actual semaphore.
This line:
static struct semaphore *sem;
creates a pointer to a semaphore, not a semaphore itself. It's almost certain initialized to NULL.
You probably want something like
static struct semaphore sem;
and therefore
sema_init( &sem, 1);
along with
up( &sem );
and
down( &sem );
Note that these calls are taking the address of an actual semaphore.

Creating a simple write only proc entry in kernel

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include<linux/sched.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
char *msg;
ssize_t write_proc(struct file *filp,const char *buf,size_t count,loff_t *offp)
{
copy_from_user(msg,buf,count);
printk(KERN_INFO "%s",msg);
return count;
}
struct file_operations proc_fops = {
write: write_proc
};
int proc_init (void) {
proc_create("write",0,NULL,&proc_fops);
return 0;
}
void proc_cleanup(void) {
remove_proc_entry("write",NULL);
}
MODULE_LICENSE("GPL");
module_init(proc_init);
module_exit(proc_cleanup);
When I used the command echo 'hello' > /proc/write Nothing show up on terminal . Can you help me to find mistakes in the code ? The string that I writed on it should have show up on terminal.
Example :
$ echo 'hello' > /proc/write
hello
Here are some simple modifications on your code:
#define MSG_SIZE (512)
static char *msg;
#define ourmin(a,b) (((a)<(b)) ? (a) : (b))
ssize_t write_proc(struct file *filp,const char *buf,size_t count,loff_t *offp)
{
unsigned long actual_len = ourmin(count, MSG_SIZE-1);
memset(msg, 0, MSG_SIZE);
copy_from_user(msg, buf, actual_len);
printk(KERN_DEBUG "Got: %s",msg);
return count;
}
int proc_init (void) {
// Allocate space for msg
if ((msg = kmalloc(MSG_SIZE, GFP_KERNEL)) == NULL)
return -ENOMEM;
// Should check the output of this too
proc_create("write",0,NULL,&proc_fops);
return 0;
}
void proc_cleanup(void) {
remove_proc_entry("write",NULL);
kfree(msg);
}
I could retrieve the output in the kernel log (dmesg for instance).

Linux kernel module - IOCTL usage returns ENOTTY

Im working on little kernel module. Im trying to use IOCTL (in ioctl_add), but I get ENOTTY when I call it, which is checked in switch, on the bottom of main. The code is below. Has anyone got any idea what am I doing wrong?
user.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#define IOCTL_TYPE (100)
#define IOCTL_ADD (_IO(IOCTL_TYPE, 1))
void cleanup()
{
if(f>=0) {
close(f);
}
}
int ioctl_add(int f)
{
int ret;
ret = ioctl(f, IOCTL_ADD);
printf("Add \n");
return ret;
}
int main(int argc, char * argv[])
{
int fd;
int *ptr;
fd = open(argv[1], O_RDWR);
if (fd < 0) {
perror("error");
}
posix_memalign((void **)&ptr, 4096, 4096);
* ptr = atoi(argv[2]);
write(fd, ptr, 4096);
ioctl_add(fd);
printf("data is %d\n", *ptr);
close(fd);
switch(errno){
case EBADF:
printf("errno: EBADF \n");
break;
case EFAULT:
printf("errno: EFAULT \n");
break;
case EINVAL:
printf("errno: EINVAL \n");
break;
case ENOTTY:
printf("errno: ENOTTY \n");
break;
default:
printf("errno: none \n");
return 0;
}
return 0;
}
module.c:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
//#include <linux/mm.h>
//#include <linux/config.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <linux/ioctl.h>
#define IOCTL_TYPE (100)
#define IOCTL_ADD (_IO(IOCTL_TYPE, 1))
#include <linux/mm.h>
#include <linux/pagemap.h>
#define DEVICE_NAME "acc_priv"
MODULE_LICENSE("GPL v2");
int ress, tmp;
struct page *page;
int *myaddr;
ssize_t acc_read(struct file *filp,
char __user *buf, size_t count,loff_t * off)
{
printk (KERN_ALERT "Opened\n\r");
return 0;
}
ssize_t acc_write(struct file *filp,
const char __user *buf, size_t count,loff_t * off)
{
printk (KERN_ALERT "Write\n\r");
printk(KERN_INFO "%s\n", __FUNCTION__);
down_read(&current->mm->mmap_sem);
ress = get_user_pages(current, current->mm,(unsigned long)buf,1,1,1,&page,NULL);
if (ress) {
printk(KERN_INFO "Got mmaped.\n");
myaddr = kmap(page);
printk(KERN_INFO "%d\n", *myaddr);
tmp = *myaddr;
tmp = tmp * 2;
printk(KERN_INFO "the result of multiplying: %d\n", tmp);
* myaddr = tmp;
page_cache_release(page);
}
up_read(&current->mm->mmap_sem);
return (0);
}
static int acc_open(struct inode *inode,
struct file *file)
{
printk(KERN_INFO "Opened inode:%p, file:%p\n", inode, file);
return 0;
}
long acc_ioctl(struct file *filp,
unsigned int cmd,unsigned long arg)
{
if(cmd == IOCTL_ADD)
printk(KERN_INFO "Do specified job \n");
return 0;
{
int acc_release(struct inode *inode,
struct file *file)
{
printk (KERN_INFO "device_release(%p,%p)\n", inode, file);
return 0;
}
struct file_operations Fops = {
.owner=THIS_MODULE,
.read=acc_read,
.write=acc_write,
.open=acc_open,
.unlocked_ioctl=acc_ioctl,
.release=acc_release,
};
dev_t my_dev=0;
struct cdev * my_cdev = NULL;
static struct class *class_acc_priv = NULL;
void clean_up(void)
{
if(my_dev && class_acc_priv) {
device_destroy(class_acc_priv,my_dev);
}
if(my_cdev) {
cdev_del(my_cdev);
my_cdev=NULL;
}
if(my_dev) {
unregister_chrdev_region(my_dev, 1);
}
if(class_acc_priv) {
class_destroy(class_acc_priv);
class_acc_priv=NULL;
}
}
int init_acc_priv(void)
{
int res=0;
res=alloc_chrdev_region(&my_dev, 0, 1, DEVICE_NAME);
if(res) {
printk (KERN_ALERT "Alocation of the device number for %s failed\n",
DEVICE_NAME);
return res;
};
class_acc_priv = class_create(THIS_MODULE, "acc_class");
if (IS_ERR(class_acc_priv)) {
printk(KERN_ERR "Error creating rs_class.\n");
res=PTR_ERR(class_acc_priv);
goto err1;
}
my_cdev = cdev_alloc( );
my_cdev->ops = &Fops;
my_cdev->owner = THIS_MODULE;
res=cdev_add(my_cdev, my_dev, 1);
if(res) {
printk (KERN_ALERT "Registration of the device number for %s failed\n",
DEVICE_NAME);
res=-EFAULT;
goto err1;
};
device_create(class_acc_priv,NULL,my_dev,NULL,"acc_priv%d",MINOR(my_dev));
printk (KERN_ALERT "%s The major device number is %d.\n",
"Registeration is a success.",
MAJOR(my_dev));
return res;
err1:
clean_up();
return res;
}
module_init(init_acc_priv);
void cleanup_acc_priv( void )
{
clean_up();
}
module_exit(cleanup_acc_priv);
When 32bit application is run on 64bit OS, it uses compat_ioctl syscall instead of unlocked_ioctl one for perform ioctl command. The reason of special syscall is that size of ioctl argument may differ for 64bit and 32bit applications.
So you need to implement .compat_ioctl file operation.

Resources