Hi all
I`ve written my first character device which can read and write. I think that read and write functions are ok but it seems to be some errors during initialization my device. Here is the source code:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
static int FirstModuleInit(void);
static void FirstModuleExit(void);
static int FirstModule_Open(struct inode *, struct file *);
static int FirstModule_Release(struct inode *, struct file *);
static ssize_t FirstModule_Read(struct file *, char *, size_t, loff_t *);
static ssize_t FirstModule_Write(struct file *, const char *, size_t, loff_t *);
#define DEV_LICENSE "GPL"
#define SUCCESS 0
#define DEVICE_NAME "mydevice"
#define BUF_LEN 128
static int Major;
static int Device_Open = 0;
static char msg[BUF_LEN];
static char *msg_Ptr;
static struct cdev* my_cdev;
static struct file_operations fops = {
.read = FirstModule_Read,
.write = FirstModule_Write,
.open = FirstModule_Open,
.release = FirstModule_Release
};
static int FirstModuleInit(void)
{
int result, err;
dev_t dev = 0;
result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
Major = MAJOR(dev);
if (result < 0 ) {
printk(KERN_WARNING "First: unable to get major number-> %d",Major);
return result;
}
cdev_init(my_cdev, &fops);
my_cdev->owner = THIS_MODULE;
my_cdev->ops = &fops;
err = cdev_add(my_cdev, dev, 1);
if (err)
printk(KERN_NOTICE "Error during adding %s device", DEVICE_NAME);
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "My dev = %d", dev);
printk(KERN_INFO "'mknod /dev/%s c %d 0'\n", DEVICE_NAME, Major);
return SUCCESS;
}
static void FirstModuleExit(void)
{
cdev_del(my_cdev);
}
static int FirstModule_Open(struct inode *inode, struct file *file)
{
static int counter = 0;
if(Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I`ve already told you %d times Hello World!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static int FirstModule_Release(struct inode *inode, struct file *file)
{
Device_Open--;
module_put(THIS_MODULE);
return 0;
}
static ssize_t FirstModule_Read(struct file *flip, 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 ssize_t FirstModule_Write(struct file *flip, const char *buffer, size_t length, loff_t *off)
{
int i;
for(i=0; i < length && i < BUF_LEN; i++)
get_user(msg[i],buffer+i);
msg_Ptr = msg;
printk(KERN_INFO "Your message from Userland is: %s",msg);
return i;
}
/*licence of the module*/
module_init(FirstModuleInit);
module_exit(FirstModuleExit);
MODULE_LICENSE(DEV_LICENSE);
MODULE_AUTHOR("Bartosz Dolewski");
MODULE_DESCRIPTION("Simple char device ");
MODULE_SUPPORTED_DEVICE("TestDevice");
I guess that I made something wrong with major and minor numbers or with dev_t dev. I just wanted to dynamically register this device not at compile time. Here is dmesg output message:
RIP: 0010:[<ffffffff803142e0>] [<ffffffff803142e0>] memset_c+0x20/0x30
RSP: 0018:ffff81002cca7e20 EFLAGS: 00010212
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 000000000000000d
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffff81002fecc6c0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000200200 R11: 0000000000000001 R12: ffffffff88384ba0
R13: 0000000000000011 R14: ffffc200004f3b98 R15: 0000000000000001
FS: 00002b2c2017a6e0(0000) GS:ffff8100375f8ac0(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000000000000 CR3: 0000000036098000 CR4: 00000000000006e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process insmod (pid: 3325, threadinfo ffff81002cca6000, task ffff8100376a9800)
Stack: ffffffff8029a6cf 0000000000000001 0000000000000000 ffffffff88384c80
ffffffff88384102 0000000000000011 0fa00000004f3b98 ffffffff88384c80
ffffffff80256c30 0000000000002ac7 0000000000000000 0000000000000000
Call Trace:
[<ffffffff8029a6cf>] cdev_init+0x19/0x3e
[<ffffffff88384102>] :first:FirstModuleInit+0x61/0xe4
[<ffffffff80256c30>] sys_init_module+0x16e3/0x1821
[<ffffffff8020be2e>] system_call+0x7e/0x83
Code: f3 48 ab 44 89 c1 f3 aa 4c 89 c8 c3 0f 1f 40 00 eb ce 66 66
RIP [<ffffffff803142e0>] memset_c+0x20/0x30
RSP <ffff81002cca7e20>
CR2: 0000000000000000
---[ end trace adc72f43f989e1df ]---
Of course insmod failed with "Terminated" message. I was learning from http://tldp.org/LDP/lkmpg/2.6/html/x569.html but as far as I know there are old way (register_chrdev()). I would like to use new structure cdev but I can see it is to sophisticated for me.
Thanks for any help
--
-----BEGIN GEEK CODE BLOCK-----
GCS d- s:- a--- C+++ P L+++>+++++ E---- W+ N+ o? K- w--- O- M- V? PS++ PE++ Y PGP++ t--- 5? X R tv-- b+ DI+ D- G++ e- h! !r(--) !z+
------END GEEK CODE BLOCK------
I`ve written my first character device which can read and write. I think that read and write functions are ok but it seems to be some errors during initialization my device. Here is the source code:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
static int FirstModuleInit(void);
static void FirstModuleExit(void);
static int FirstModule_Open(struct inode *, struct file *);
static int FirstModule_Release(struct inode *, struct file *);
static ssize_t FirstModule_Read(struct file *, char *, size_t, loff_t *);
static ssize_t FirstModule_Write(struct file *, const char *, size_t, loff_t *);
#define DEV_LICENSE "GPL"
#define SUCCESS 0
#define DEVICE_NAME "mydevice"
#define BUF_LEN 128
static int Major;
static int Device_Open = 0;
static char msg[BUF_LEN];
static char *msg_Ptr;
static struct cdev* my_cdev;
static struct file_operations fops = {
.read = FirstModule_Read,
.write = FirstModule_Write,
.open = FirstModule_Open,
.release = FirstModule_Release
};
static int FirstModuleInit(void)
{
int result, err;
dev_t dev = 0;
result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
Major = MAJOR(dev);
if (result < 0 ) {
printk(KERN_WARNING "First: unable to get major number-> %d",Major);
return result;
}
cdev_init(my_cdev, &fops);
my_cdev->owner = THIS_MODULE;
my_cdev->ops = &fops;
err = cdev_add(my_cdev, dev, 1);
if (err)
printk(KERN_NOTICE "Error during adding %s device", DEVICE_NAME);
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "My dev = %d", dev);
printk(KERN_INFO "'mknod /dev/%s c %d 0'\n", DEVICE_NAME, Major);
return SUCCESS;
}
static void FirstModuleExit(void)
{
cdev_del(my_cdev);
}
static int FirstModule_Open(struct inode *inode, struct file *file)
{
static int counter = 0;
if(Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I`ve already told you %d times Hello World!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static int FirstModule_Release(struct inode *inode, struct file *file)
{
Device_Open--;
module_put(THIS_MODULE);
return 0;
}
static ssize_t FirstModule_Read(struct file *flip, 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 ssize_t FirstModule_Write(struct file *flip, const char *buffer, size_t length, loff_t *off)
{
int i;
for(i=0; i < length && i < BUF_LEN; i++)
get_user(msg[i],buffer+i);
msg_Ptr = msg;
printk(KERN_INFO "Your message from Userland is: %s",msg);
return i;
}
/*licence of the module*/
module_init(FirstModuleInit);
module_exit(FirstModuleExit);
MODULE_LICENSE(DEV_LICENSE);
MODULE_AUTHOR("Bartosz Dolewski");
MODULE_DESCRIPTION("Simple char device ");
MODULE_SUPPORTED_DEVICE("TestDevice");
I guess that I made something wrong with major and minor numbers or with dev_t dev. I just wanted to dynamically register this device not at compile time. Here is dmesg output message:
RIP: 0010:[<ffffffff803142e0>] [<ffffffff803142e0>] memset_c+0x20/0x30
RSP: 0018:ffff81002cca7e20 EFLAGS: 00010212
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 000000000000000d
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffff81002fecc6c0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000200200 R11: 0000000000000001 R12: ffffffff88384ba0
R13: 0000000000000011 R14: ffffc200004f3b98 R15: 0000000000000001
FS: 00002b2c2017a6e0(0000) GS:ffff8100375f8ac0(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000000000000 CR3: 0000000036098000 CR4: 00000000000006e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process insmod (pid: 3325, threadinfo ffff81002cca6000, task ffff8100376a9800)
Stack: ffffffff8029a6cf 0000000000000001 0000000000000000 ffffffff88384c80
ffffffff88384102 0000000000000011 0fa00000004f3b98 ffffffff88384c80
ffffffff80256c30 0000000000002ac7 0000000000000000 0000000000000000
Call Trace:
[<ffffffff8029a6cf>] cdev_init+0x19/0x3e
[<ffffffff88384102>] :first:FirstModuleInit+0x61/0xe4
[<ffffffff80256c30>] sys_init_module+0x16e3/0x1821
[<ffffffff8020be2e>] system_call+0x7e/0x83
Code: f3 48 ab 44 89 c1 f3 aa 4c 89 c8 c3 0f 1f 40 00 eb ce 66 66
RIP [<ffffffff803142e0>] memset_c+0x20/0x30
RSP <ffff81002cca7e20>
CR2: 0000000000000000
---[ end trace adc72f43f989e1df ]---
Of course insmod failed with "Terminated" message. I was learning from http://tldp.org/LDP/lkmpg/2.6/html/x569.html but as far as I know there are old way (register_chrdev()). I would like to use new structure cdev but I can see it is to sophisticated for me.
Thanks for any help
--
-----BEGIN GEEK CODE BLOCK-----
GCS d- s:- a--- C+++ P L+++>+++++ E---- W+ N+ o? K- w--- O- M- V? PS++ PE++ Y PGP++ t--- 5? X R tv-- b+ DI+ D- G++ e- h! !r(--) !z+
------END GEEK CODE BLOCK------