i am new in linux kernel module developpement and i am searching for sharing a memory segment from kernel module to user space process to escape latency of copying data.
i am using the sys v shared memory api, when i share memory between two process it's work fine, but i am not able to share memory between process and kernel module.
bellow is my code of the kernel module and the user space app
server side : module
#include <linux/module.h> // init_module, cleanup_module //
#include <linux/kernel.h> // KERN_INFO //
#include <linux/types.h> // uint64_t //
#include <linux/kthread.h> // kthread_run, kthread_stop //
#include <linux/delay.h> // msleep_interruptible //
#include <linux/syscalls.h> // sys_shmget //
#define BUFSIZE 100
#define SHMSZ BUFSIZE*sizeof(char)
key_t KEY = 5678;
static struct task_struct *shm_task = NULL;
static char *shm = NULL;
static int shmid;
static int run_thread( void *data )
{
char strAux[BUFSIZE];
shmid = sys_shmget(KEY, SHMSZ, IPC_CREAT | 0666);
if( shmid < 0 )
{
printk( KERN_INFO "SERVER : Unable to obtain shmid\n" );
return -1;
}
shm = sys_shmat(shmid, NULL, 0);
if( !shm )
{
printk( KERN_INFO "SERVER : Unable to attach to memory\n" );
return -1;
}
strncpy( strAux, "hello world from kernel module", BUFSIZE );
memcpy(shm, strAux, BUFSIZE);
return 0;
}
int init_module()
{
printk( KERN_INFO "SERVER : Initializing shm_server\n" );
shm_task = kthread_run( run_thread, NULL, "shm_server" );
return 0;
}
void cleanup_module()
{
int result;
printk( KERN_INFO "SERVER : Cleaning up shm_server\n" );
result = kthread_stop( shm_task );
if( result < 0 )
{
printk( KERN_INFO "SERVER : Unable to stop shm_task\n" );
}
result = sys_shmctl( shmid, IPC_RMID, NULL );
if( result < 0 )
{
printk( KERN_INFO
"SERVER : Unable to remove shared memory from system\n" );
}
}
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( " MBA" );
MODULE_DESCRIPTION( "Shared memory server" );
client side : process
#include <sys/ipc.h> // IPC_CREAT, ftok //
#include <sys/shm.h> // shmget, ... //
#include <sys/sem.h> // semget, semop //
#include <stdio.h> // printf //
#include <string.h> // strcpy //
#include <stdint.h> // uint64_t //
#define BUFSIZE 4096
key_t KEY = 5678;
int main(int argc, char *argv[]) {
int shmid, result;
char *shm = NULL;
shmid = shmget(KEY, BUFSIZE, 0666);
if (shmid == -1) {
perror("shmget");
exit(-1);
}
shm = shmat(shmid, NULL, 0);
if (!shm) {
perror("shmat");
exit(-1);
}
printf("%s\n", shm);
result = shmdt(shm);
if (result < 0) {
perror("shmdt");
exit(-1);
}
}
any suggestion or document can help.
System calls are not intended for being use by the kernel: they are for user programs only. Also, it is unlikely that is sys v memory sharing works for kernel threads.
Kernel and kernel modules have their own mechanism for interract with user
space. For sharing memory, your kernel module may implement character device and mmap method for it, which maps kernel's allocated memory to user. See example of such mmap implementation in Linux Device Drivers(3d edition), Chapter 15.
Related
Specific GPIO pin is connected to switch, upon pressing the switch the ISR needs to triggered. So I have the user space application to read the ISR, but I am getting the ISR on both the edges.
Receiving the interrupt when switch is pressed and also when released. How to configure to receive the ISR only on rising edge
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
int main(int argc, char *argv[]) {
int fd;
char value;
struct pollfd poll_gpio;
poll_gpio.events = POLLPRI;
// export GPIO
fd = open ("/sys/class/gpio/export", O_WRONLY);
write (fd, "44", 4);
close (fd);
// configure as input
fd = open ("/sys/class/gpio/gpio44/direction", O_WRONLY);
write (fd, "in", 3);
close (fd);
// configure interrupt
fd = open ("/sys/class/gpio/gpio44/edge", O_WRONLY);
write (fd, "rising", 7); // configure as rising edge
close (fd);
// open value file
fd = open("/sys/class/gpio/gpio44/value", O_RDONLY );
poll_gpio.fd = fd;
poll (&poll_gpio, 1, -1); // discard first IRQ
read (fd, &value, 1);
// wait for interrupt
while (1) {
poll (&poll_gpio, 1, -1);
if ((poll_gpio.revents & POLLPRI) == POLLPRI) {
lseek(fd, 0, SEEK_SET);
read (fd, &value, 1);
usleep (50);
printf("Interrupt GPIO val: %c\n", value);
}
}
close(fd); //close value file
return EXIT_SUCCESS;
}
I used gpio test driver also to test the ISR, but even in driver code I am getting ISR on both edges when the switch is pressed
Here is the gpio test driver code
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("");
MODULE_DESCRIPTION("A Button driver for the GPIO Switch");
MODULE_VERSION("0.1");
#define GPIO_NUM 44
#define GPIO_KEY_NAME "GPIO_INT_KEY"
static int irq;
/* interrupt handler*/
static irqreturn_t gpio_int_key_isr(int irq, void *dev_id)
{
printk(KERN_INFO "GPIO:Interrupt received. key: %s\n", GPIO_KEY_NAME);
return IRQ_HANDLED;
}
static int __init gpio_test_probe(struct platform_device *pdev)
{
int ret_val;
struct device *dev = &pdev->dev;
printk(KERN_INFO "GPIO Platform_probe enter\n");
gpio_request(GPIO_NUM, "sysfs");
gpio_direction_input(GPIO_NUM);
gpio_set_debounce(GPIO_NUM, 200);
gpio_export(GPIO_NUM, false);
irq = gpio_to_irq(GPIO_NUM);
if (irq < 0)
{
pr_err("IRQ is not available\n");
return -EINVAL;//1;
}
printk(KERN_INFO "IRQ using gpio_to_irq: %d\n", irq);
/*Register the interrupt handler*/
ret_val = devm_request_irq(dev, irq, gpio_int_key_isr, IRQF_TRIGGER_RISING, GPIO_KEY_NAME, pdev->dev.of_node);
if(ret_val)
{
pr_err("Failed to request GPIO interrupt %d, error %d\n",irq, ret_val);
return ret_val;
}
return 0;
}
static int __exit gpio_test_remove(struct platform_device *pdev)
{
pr_info("%s function is called. \n",__func__);
return 0;
}
/*Declare list of devices supported by the driver*/
static const struct of_device_id my_of_ids[] = {
{ .compatible = "gpio-intr-key"},
{},
};
MODULE_DEVICE_TABLE(of, my_of_ids);
/*Define platform driver structure*/
static struct platform_driver my_platform_driver = {
.probe = gpio_test_probe,
.remove = gpio_test_remove,
.driver = {
.name = "gpioIntrKey",
.of_match_table = of_match_ptr(my_of_ids),
.owner = THIS_MODULE,
}
};
module_platform_driver(my_platform_driver);
Below is the dts entry
gpio_test {
compatible = "gpio-intr-key";
gpio = <&gpio2a 44>;
interrupt-controller;
interrupt-parent = <&gpio2a>;
interrupts = <44 IRQ_TYPE_EDGE_RISING>;
status = "okay";
};
Disclaimer - I have to admit that it's the 1'st time I'm using this kernel interface (socket).
I'm currently working on a design of a kernel module that is based on a netlink socket .
I'm using Ubuntu14.04 and linux kernel 4.
As a starter, I wanted to make sure that I can use the netlink socket in both directions.
I've written an application that does the following:
1) User send a message to kernel via the netlink socket.
2) Kernel, upon receiving the message – sends "ABCD" string message to a workqueue.
3) When the "ABCD" message is received by the workqueue, it calls a function (named - my_wq_function) which send it back to the user space via netlink socket.
4) In the user space I'm using a recvmsg function (blocking until a message is received) and displays the "ABCD" message.
My problem is that the return value from the recvmsg function is 20 (instead of 4), and the data itself (i.e. NLMSG_DATA) is empty.
During the debug I tried to change the message to "ABCD1234" and got a return value of 24 bytes, however the data is still empty.
I also verified that my entire path until the point of sending the "ABCD" from kernel to the socket is OK.
Not sure what I'm doing wrong here & will highly appreciate your help.
Thanks in advance, MotiC.
my code example can be found below:
User space code:
printf("netlink receiver thread started...\n");
nlh_rcv = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
while(true) //endless loop on netlink socket
{
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_base = (void *)nlh_rcv;
iov_rcv.iov_len = nlh_rcv->nlmsg_len;
msg_rcv.msg_name = (void *)&dest_addr;
msg_rcv.msg_namelen = sizeof(dest_addr);
msg_rcv.msg_iov = &iov;
msg_rcv.msg_iovlen = 1;
ret=recvmsg(sock_fd, &msg_rcv, 0);
printf("errno=%i bytes=%i message from kernel: %s\n",errno, ret, (char*)NLMSG_DATA(nlh_rcv));
uint8_t mymsg[100];
memcpy(mymsg, NLMSG_DATA(nlh_rcv), 100);
printf("message from kernel: %s\n",mymsg);
}
Kernel space code:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
#include "rf_Kdriver_main.h"
//------ definitions ------------------------------------------------------------------------------------------------------------
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sock *nl_sk = NULL;
struct nlmsghdr *nlh;
struct nlmsghdr *nlh_out;
struct sk_buff *skb_out;
char buf_to_user[100];
int pid;
//------------------------------------------------------------------------------------------------------------------------------
struct workqueue_struct *my_wq;
typedef struct {
struct work_struct my_work;
uint8_t msg_to_pc[128];
uint8_t msg_len;
} my_work_t;
my_work_t *work, *work2;
//-----------------------------------------------------------------------------------------------------------------------------
static void my_wq_function( struct work_struct *work)
{
int res;
my_work_t *my_work = (my_work_t *)work;
skb_out = nlmsg_new(my_work->msg_len,0);
if (!skb_out)
{
printk("Failed to allocate new skb\n");
return;
}
nlh_out = nlmsg_put(skb_out, 0, 0, NLMSG_DONE,my_work->msg_len, 0);
NETLINK_CB(skb_out).dst_group = 0;
memcpy((char*)NLMSG_DATA(nlh_out), my_work->msg_to_pc , my_work->msg_len);
printk( "dequeue message to pc=%s len=%i\n", (char*)NLMSG_DATA(nlh_out), (int)strlen((char*)NLMSG_DATA(nlh_out)));
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res<0)
printk("Failed to send message from kernel to user\n");
kfree( (void *)work );
return;
}
//-----------------------------------------------------------------------------------------------------------------------------
int send_up_msg_to_workque(uint8_t msg_to_pc[], uint8_t msg_len)
{
int ret=0;
work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);
if (work) {
INIT_WORK( (struct work_struct *)work, my_wq_function );
memcpy(work->msg_to_pc, msg_to_pc, msg_len);
work->msg_len = msg_len;
ret = queue_work( my_wq, /*(struct work_struct *)RR*/work );
printk("kuku ret=%i msg=%s\n",ret,work->msg_to_pc);
}
return ret;
}
//------------------------------------------------------------------------------------------------------------------------------
static void netlink_recv_msg(struct sk_buff *skb)
{
char *msg = "ABCD1234";
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
nlh=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink at kernel received msg payload: %s\n",(char*)NLMSG_DATA(nlh));
//rr
pid = nlh->nlmsg_pid;
send_up_msg_to_workque((uint8_t*) msg, strlen(msg));
}
//-------------------------------------------------------------------------------------------------------------------------------------
struct netlink_kernel_cfg cfg = {
.input = netlink_recv_msg,
};
static int __init rf_driver_start(void)
{
printk(KERN_INFO "Loading RF Driver module1...\n");
my_wq = create_workqueue("my_queue");
if (!my_wq)
{
printk("Failed to create work queue\n");
}
printk("Entering: %s\n",__FUNCTION__);
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
if(!nl_sk)
{
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
return 0;
}
//--------------------------------------------------------------------------------------------------------------
static void __exit rf_driver_end(void)
{
netlink_kernel_release(nl_sk);
flush_workqueue(my_wq);
destroy_workqueue(my_wq);
printk(KERN_INFO "RF Driver exit...\n");
}
module_init(rf_driver_start);
module_exit(rf_driver_end);
Update,
I changed my user space function to:
char buf[100];
ret=recv(sock_fd, buf, 100, 0);
instead of:
ret=recvmsg(sock_fd, &msg_rcv, 0);
and it works...
does anyone have an idea regarding this strange behavior ?
Thanks.
Can you please paste complete userspace code.
I guess 'len' int this code is the issue:
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_len = nlh_rcv->nlmsg_len; << check to what value is it getting initialized.
I'm a beginner to the Linux programming and trying my hands on some device driver examples while practising.
The below code (a trimmed down version of tiny_tty.c) loads perfectly using insmod and I'm able to see it in /proc/tty/drivers , /proc/modules and device nodes are getting created under /dev. When I try to write to device file like echo "abcd" > /dev/ttyms0 (I hope this is fine) or read like cat /dev/ttyms0, the kernel panics with a call trace on the screen. I'm on kernel 3.5.0 under Ubuntu. Unfortunately I'm not able to capture the trace , as when it panics I'm left with no option but reboot using power button. I believe some issue with timer is here, as the trace shows a line on top saying :
"*kernel bug at /build/buildd/linux-3.5.0/kernel/timer.c:901*", then the call trace , followed by
"*EIP is at add_timer+0x18/0x20*"
Below is the full code. Any guidance is very much appreciated in anticipation.
10May2013 : I tried initializing the timer in open function and this time below is the call trace for "kernel panic - not syncing : fatal exception in interrupt panic occurred, switching back to text console":
update_sd_lb_stats+0xcd/0x4b0
find_busiest_group+0x2e/0x420
enqueue_entity+0xcb/0x510
load_balance+0x7e/0x5e0
rebalance_domains+0xed/0x150
__do_softirq+0xdb/0x180
local_bh_enable_ip+0x90/0x90
<IRQ>
copy_to_user0x41/0x60
sys_gettimeofday+0x2a/0x70
sysenter_do_call0x12/0x20
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/tty_driver.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mutex.h>
#include <linux/serial.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/termios.h>
MODULE_LICENSE("GPL");
#define MS_TTY_MAJOR 250 //test value
#define MS_TTY_NUM_DEV 2
#define DELAY_TIME HZ * 2 /* 2 seconds per character */
#define TINY_DATA_CHARACTER 't'
static int major_num;
//static int minor_num=0;
//static int num_tty_dev=2;
/* Below structure is a wrapper for device specific fields */
struct ms_tty_serial {
struct tty_struct *tty; /* pointer to the tty for this device */
int open_count; /* number of times this port has been opened */
struct semaphore sem; /* locks this structure */
struct timer_list *timer;
};
static struct ms_tty_serial *ms_tty_table[MS_TTY_NUM_DEV]; /* initially all NULL */
static void ms_tty_timer(unsigned long timer_data)
{
struct ms_tty_serial *ms_ptr = (struct ms_tty_serial *)timer_data;
struct tty_struct *tty;
char data[1] = {TINY_DATA_CHARACTER};
int data_size = 1;
if (!ms_ptr)
return;
tty = ms_ptr->tty;
tty->low_latency=1;
/* send the data to the tty layer for users to read. This doesn't
* actually push the data through unless tty->low_latency is set */
tty_buffer_request_room (tty, data_size);
tty_insert_flip_string(tty, data, data_size);
tty_flip_buffer_push(tty);
/* resubmit the timer again */
ms_ptr->timer->expires = jiffies + DELAY_TIME;
add_timer(ms_ptr->timer);
}
//// Define the open function ////
static int tty_ms_open(struct tty_struct *tty_this, struct file *file_this)
{
printk(KERN_ALERT "tty_ms driver: OPENED ...\n");
struct ms_tty_serial *ms_ptr;
struct timer_list *timer;
int index;
/* initialize the pointer in case something fails */
tty_this->driver_data = NULL;
/* get the serial object associated with this tty pointer */
index = tty_this->index;
ms_ptr = ms_tty_table[index];
if (ms_ptr == NULL) {
/* first time accessing this device, create it */
ms_ptr = kmalloc(sizeof(*ms_ptr), GFP_KERNEL);
if (!ms_ptr)
return -ENOMEM;
// init_MUTEX(&ms_ptr->sem); /* didn't work for this kernel version 3.5.0 */
#ifndef init_MUTEX /* sema_init is to be used for kernel 2.6.37 and above */
sema_init(&ms_ptr->sem,1);
#else
init_MUTEX(&ms_ptr->sem);
#endif
ms_ptr->open_count = 0;
ms_ptr->timer = NULL;
ms_tty_table[index] = ms_ptr;
}
down(&ms_ptr->sem);
/* save our structure within the tty structure */
tty_this->driver_data = ms_ptr;
ms_ptr->tty = tty_this;
ms_ptr->filp = file_this; // to be tried
++ms_ptr->open_count;
if (ms_ptr->open_count == 1) {
/* this is the first time this port is opened */
/* do any hardware initialization needed here */
/* create timer and submit it */
if (!ms_ptr->timer) {
timer = kmalloc(sizeof(*timer), GFP_KERNEL);
if (!timer) {
up(&ms_ptr->sem);
return -ENOMEM;
}
ms_ptr->timer = timer;
}
init_timer (ms_ptr->timer); // to be tried
ms_ptr->timer->data = (unsigned long )ms_ptr;
ms_ptr->timer->expires = jiffies + DELAY_TIME;
ms_ptr->timer->function = ms_tty_timer;
add_timer(ms_ptr->timer);
}
up(&ms_ptr->sem);
return 0;
}
//// Define the close function ////
static void do_close(struct ms_tty_serial *ms_ptr)
{
down(&ms_ptr->sem);
if (!ms_ptr->open_count) {
/* port was never opened */
goto exit;
}
--ms_ptr->open_count;
if (ms_ptr->open_count <= 0) {
/* The port is being closed by the last user. */
/* Do any hardware specific stuff here */
/* shut down our timer */
del_timer(ms_ptr->timer);
}
exit:
up(&ms_ptr->sem);
}
static void tty_ms_close(struct tty_struct *tty_this, struct file *file_this)
{
printk(KERN_ALERT "tty_ms driver: CLOSING ...\n");
struct ms_tty_serial *ms_ptr = tty_this->driver_data;
if (ms_ptr)
do_close(ms_ptr);
}
//// Define the write function ////
static int tty_ms_write(struct tty_struct *tty_this, const unsigned char *tty_buff, int count)
{
printk(KERN_ALERT "tty_ms driver: WRITING ...\n");
struct ms_tty_serial *ms_ptr = tty_this->driver_data;
int i;
int retval = -EINVAL;
if (!ms_ptr)
return -ENODEV;
down(&ms_ptr->sem);
if (!ms_ptr->open_count)
/* port was not opened */
{
up(&ms_ptr->sem);
return retval;
}
/* fake sending the data out a hardware port by
* writing it to the kernel debug log.
*/
printk(KERN_DEBUG "%s - ", __FUNCTION__);
for (i = 0; i < count; ++i)
printk("%02x ", tty_buff[i]);
printk("\n");
return 0;
}
// Define the operations for tty driver in tty_operations struct //
static struct tty_operations tty_ms_ops = {
.open = tty_ms_open,
.close = tty_ms_close,
.write = tty_ms_write,
//.set_termios = tty_ms_set_termios,
};
///////////////////////////////////////// Module Initialization Starts ////////////////////////////////////
static struct tty_driver *tty_ms_driver;
static int tty_ms_init(void)
{
// static int result;
static int retval,iter;
// Allocate the tty_driver struct for this driver //
tty_ms_driver = alloc_tty_driver(MS_TTY_NUM_DEV);
if (!tty_ms_driver)
return -ENOMEM; // Error NO Memory , allocation failed
else
printk(KERN_INFO "tty_driver structure allocated..!!"); //debug line
// Initialize the allocated tty_driver structure //
tty_ms_driver->magic=TTY_DRIVER_MAGIC;
tty_ms_driver->owner = THIS_MODULE;
tty_ms_driver->driver_name = "tty_ms";
tty_ms_driver->name = "ttyms";
tty_ms_driver->major = MS_TTY_MAJOR,
tty_ms_driver->type = TTY_DRIVER_TYPE_SERIAL,
tty_ms_driver->subtype = SERIAL_TYPE_NORMAL,
tty_ms_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV,
tty_ms_driver->init_termios = tty_std_termios;
tty_ms_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(tty_ms_driver, &tty_ms_ops);
printk(KERN_INFO "allocated tty_driver structure -INITIALIZED."); //debug line
//// Register this driver with the tty core ////
retval = tty_register_driver(tty_ms_driver);
if (retval) {
printk(KERN_ERR "failed to register tty_ms driver\n tty registration returned %d", retval);
put_tty_driver(tty_ms_driver);
return retval;
}
//// Register the tty devices(nodes) with the tty core ////
for (iter = 0; iter < MS_TTY_NUM_DEV ; ++iter)
tty_register_device(tty_ms_driver, iter, NULL);
return 0; // All initializations done
} // init func ends
///////////////////////////////////////// Module Initialization Ends ////////////////////////////////////
///////////////////////////////////////// Module cleanup Starts ////////////////////////////////////
static void tty_ms_terminate(void)
{
static int iter;
struct ms_tty_serial *tty_ser;
printk(KERN_ALERT "tty_ms driver: Unloading...\n");
for(iter=1;iter<=MS_TTY_NUM_DEV;iter++)
tty_unregister_device(tty_ms_driver,iter); //unregister all the devices, from tty layer
tty_unregister_driver(tty_ms_driver); // Now unregister the driver from tty layer
/* shut down all of the timers and free the memory */
for (iter = 0; iter < MS_TTY_NUM_DEV; ++iter) {
tty_ser = ms_tty_table[iter];
if (tty_ser) {
/* close the port */
while (tty_ser->open_count)
do_close(tty_ser);
/* shut down our timer and free the memory */
del_timer(tty_ser->timer);
kfree(tty_ser->timer);
kfree(tty_ser);
ms_tty_table[iter] = NULL;
}
}
dev_t devno=MKDEV(major_num,0); // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
unregister_chrdev_region(devno,MS_TTY_NUM_DEV);
}
///////////////////////////////////////// Module cleanup ends ////////////////////////////////////
module_init(tty_ms_init);
module_exit(tty_ms_terminate);
After performing the command "insmod demo_device" the modules listed in /proc/modules
**demo_device 2528 0 - Live 0xe02da000**
fp_indicators 5072 1 - Live 0xe02d2000 (P)
screader 22672 1 - Live 0xe02c5000 (P)
icamdescrambler 12912 0 - Live 0xe02b2000 (P)
icamemmfilter 16208 0 - Live 0xe02a4000 (P)
icamecmfilter 14992 0 - Live 0xe0294000 (P)
but "(P)" is not avail after that.
After firing the command cat /proc/devices the device "demo_device" is not listed there.
So my question is that: what (P) stands in (cat /proc/modules) and what could be the reason that the device is not listed in (cat /proc/devices).
Thanks in Advance !!
The source code is as:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include "query_ioctl.h"
#define FIRST_MINOR 0
#define MINOR_CNT 1
static dev_t dev;
static struct cdev c_dev;
static struct class *cl;
static int status = 1, dignity = 3, ego = 5;
static int my_open(struct inode *i, struct file *f)
{
return 0;
}
static int my_close(struct inode *i, struct file *f)
{
return 0;
}
#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
{
query_arg_t q;
switch (cmd)
{
case QUERY_GET_VARIABLES:
q.status = status;
q.dignity = dignity;
q.ego = ego;
if (copy_to_user((query_arg_t *)arg, &q, sizeof(query_arg_t)))
{
return -EACCES;
}
break;
case QUERY_CLR_VARIABLES:
status = 0;
dignity = 0;
ego = 0;
break;
case QUERY_SET_VARIABLES:
if (copy_from_user(&q, (query_arg_t *)arg, sizeof(query_arg_t)))
{
return -EACCES;
}
status = q.status;
dignity = q.dignity;
ego = q.ego;
break;
default:
return -EINVAL;
}
return 0;
}
static struct file_operations query_fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
.ioctl = my_ioctl
#else
.unlocked_ioctl = my_ioctl
#endif
};
static int __init query_ioctl_init(void)
{
int ret;
struct device *dev_ret;
printk("Before calling alloc\n");
dev=150;
if ((ret = register_chrdev_region(dev, MINOR_CNT, "demo_device")))
{
return ret;
}
else if((ret = alloc_chrdev_region(&dev,0,MINOR_CNT,"demo_device")))
{
return ret;
}
printk("After alloc %d %d\n",ret,dev);
cdev_init(&c_dev, &query_fops);
if ((ret = cdev_add(&c_dev, dev, MINOR_CNT)) < 0)
{
return ret;
}
printk("After cdev_add\n");
if (IS_ERR(cl = class_create(THIS_MODULE, "char")))
{
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
return PTR_ERR(cl);
}
printk("After class_create\n");
if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, "demo")))
{
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
return PTR_ERR(dev_ret);
}
printk("After device_create\n");
return 0;
}
static void __exit query_ioctl_exit(void)
{
device_destroy(cl, dev);
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
}
module_init(query_ioctl_init);
module_exit(query_ioctl_exit);
MODULE_LICENSE("GPL");
And after inserting the module I am able to see these messages:
$insmod demo_device.ko
Before calling alloc
After alloc 0 217055232
After cdev_add
After class_create
After device_create
$
Make sure that Major Number of the device is not preoccupied by some other device file. use the following command to check the occupied Major Numbers
cat /proc/devices
Use the following code to capture initialization error in init function
int t=register_chrdev(majorNumber,"mydev",&fops);
if(t<0)
printk(KERN_ALERT "device registration failed.");
Use dmesg to look into kernel logs
Look at module_flags_taint() in kernel/module.c.
The 'P' flag merely indicated the other modules are proprietary. The reason your device doesn't show up in /proc/devices is probably because something is wrong with the initialisation, but we can't help you with that unless you show us code.
After perfroming make clean to the linux/application source code and rebuilding it again...make it works. Now after inserting the module the corresponding entry is visibe in the /proc/devcies file :)
There some bugs reading from the user space with this application. Is my copy_to_user dont correctly?
The following is the readout from terminal:
Press r to read from device or w to write the device r
0x-1075024108 0x15123440 0xe70401 0xe6f8dc 0xe73524
0x0 0x15037588 0xbfec6f14 0xe57612 0xbfec6f34
0x15037140 0x2 0xe57334 0xc6d690 0xd696910
0x-1075024080 0x15071734 0xc737c9 0x804835a 0x2
The following is the code from apps layer:
read(fd, read_buf, sizeof(read_buf));
for(i=0;i<=(BUFF_SIZE / sizeof(int));i+=5)
printf(" 0x%x 0x%x 0x%x 0x%x 0x%x \n",
read_buf[i],read_buf[i+1],read_buf[i+2],
read_buf[i+3],read_buf[i+4]);
break;
and the following is my driver code:
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#ifdef MODVERSIONS
# include <linux/modversions.h>
#endif
#include <asm/io.h>
#include <asm/uaccess.h> // required for copy_from and copy_to user
/* character device structures */
static dev_t mmap_dev;
static struct cdev mmap_cdev;
/* methods of the character device */
static int mmap_open(struct inode *inode, struct file *filp);
static int mmap_release(struct inode *inode, struct file *filp);
/* the file operations, i.e. all character device methods */
static struct file_operations mmap_fops = {
.open = mmap_open,
.release= mmap_release,
.owner = THIS_MODULE,
};
static int *vmalloc_area;
#define NPAGES 1//16
#define BUFF_SIZE 64 // bytes
/* character device open method */
static int mmap_open(struct inode *inode, struct file *filp)
{
return 0;
}
/* character device last close method */
static int mmap_release(struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t read(struct file *filp, int *buff, size_t count, loff_t *offp)
{
unsigned long bytes_left;
printk("Inside read \n");
bytes_left = copy_to_user(buff, vmalloc_area , count);
if(bytes_left<0)
bytes_left = -EFAULT;
return bytes_left;
}
/* module initialization - called at module load time */
static int __init membuff_init(void)
{
int ret = 0, i =0;
printk(KERN_ERR "#membuff_init\n");
/* allocate a memory area with vmalloc. */
if ((vmalloc_area = vmalloc(BUFF_SIZE)) == NULL) {
ret = -ENOMEM;
goto out_vfree;
}
/* get the major number of the character device */
if( (ret = alloc_chrdev_region(&mmap_dev, 0, 1, "mmap")) < 0) {
printk(KERN_ERR "#membuff_init could not allocate major number for mmap\n");
goto out_vfree;
}
printk(KERN_ERR "#membuff_init Major number for mmap: %d\n",MAJOR(mmap_dev));
/* initialize the device structure and register the device with the kernel */
cdev_init(&mmap_cdev, &mmap_fops);
if ((ret = cdev_add(&mmap_cdev, mmap_dev, 1)) < 0) {
printk(KERN_ERR "#membuff_init could not allocate chrdev for mmap\n");
goto out_unalloc_region;
}
for (i = 0; i < (BUFF_SIZE / sizeof(int)); i +=1) {
vmalloc_area[i] = i;
printk(KERN_ERR "#membuff_init: %d\n",vmalloc_area[i]);
}
return ret;
out_unalloc_region:
unregister_chrdev_region(mmap_dev, 1);
out_vfree:
if(vmalloc_area)
vfree(vmalloc_area);
return ret;
}
/* module unload */
static void __exit mmap_exit(void)
{
if(vmalloc_area)
vfree(vmalloc_area);
/* remove the character deivce */
cdev_del(&mmap_cdev);
unregister_chrdev_region(mmap_dev, 1);
printk(KERN_ERR "#mmap_exit\n");
}
module_init(membuff_init);
module_exit(mmap_exit);
MODULE_DESCRIPTION("trying out copy_to_user");
MODULE_LICENSE("Dual BSD/GPL");