I am using i.mx6quad with debian jessie (3.14.60-fslc-imx6-sr).
I want co connect ov5642 camera module with PARALLEL 8BIT interface (using 8gpios for data and 3 for control signals).
I wrote a linux kernel module to service interrupts from control signals. Interrupts from VSYNC and HREF signals are serviced properly but when I connect a PCLK (about 8MHz) signal which is much faster than HREF or VSYNC my linux hangs up untill I disconnect a wire with PCLK (everything stucks).
To connect PCLK I use GPIO90 (DISP1_DATA22) but I tried also with other gpios.
Now My question is which GPIO should I use to service such fast signals like PCLK properly or what can i do to avoid linux hang ups ??
I include a linux kernel module code that I use.
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/gpio.h>
#include<linux/interrupt.h>
static unsigned int VSYNC_gpio_number=79;
static unsigned int HREF_gpio_number=76;
static unsigned int PCLK_gpio_number=90;
static unsigned int VSYNC_irqNumber;
static unsigned int HREF_irqNumber;
static unsigned int PCLK_irqNumber;
static irq_handler_t VSYNC_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs);
static irq_handler_t HREF_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs);
static irq_handler_t PCLK_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs);
int __init camera_module_test_init(void){//init_module()
int result=0;
printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n");
//VSYNC init
if(!gpio_is_valid(VSYNC_gpio_number)){
printk(KERN_INFO "GPIO TEST: invalid VSYNC GPIO\n");
return -ENODEV;
}
//HREF init
if(!gpio_is_valid(HREF_gpio_number)){
printk(KERN_INFO "GPIO TEST: INVALID HREF GPIO\n");
return -ENODEV;
}
//PCLK init
if(!gpio_is_valid(PCLK_gpio_number)){
printk(KERN_INFO "GPIO TEST: INVALID PCLK GPIO\n");
return -ENODEV;
}
//ledOn=true;
//VSYNC
gpio_request(VSYNC_gpio_number,"sysfs");
gpio_direction_input(VSYNC_gpio_number);
gpio_export(VSYNC_gpio_number,false); // causes gpioX to appear in sysfs /sys/class/gpio/
//HREF
gpio_request(HREF_gpio_number,"sysfs");
gpio_direction_input(HREF_gpio_number);
gpio_export(HREF_gpio_number,false);
//PCLK
gpio_request(PCLK_gpio_number,"sysfs");
gpio_direction_input(PCLK_gpio_number);
gpio_export(PCLK_gpio_number,false);
// GPIO numbers and IRQ numbers are not the same
//MAPPING GPIO NUMBERS TO IRQ NUMBERS
//---------
VSYNC_irqNumber = gpio_to_irq(VSYNC_gpio_number);
printk(KERN_INFO "GPIO_TEST: VSYNC signal is mapped to IRQ: %d\n",VSYNC_irqNumber);
//
HREF_irqNumber=gpio_to_irq(HREF_gpio_number);
printk(KERN_INFO "GPIO TEST: HREF signal is mapped to IRQ: %d\n",HREF_irqNumber);
//
PCLK_irqNumber=gpio_to_irq(PCLK_gpio_number);
printk(KERN_INFO "GPIO TEST: PCLK signal is mapped to IRQ: %d\n",PCLK_irqNumber);
//requests an interrupt line
//VSYNC
result=request_irq(VSYNC_irqNumber,(irq_handler_t)VSYNC_gpio_irq_handler,IRQF_TRIGGER_RISING,"VSYNC_gpio_handler",NULL);
if(result==0){ //if success
printk(KERN_INFO "GPIO_TEST: The VSYNC interrupt request result is: %d\n",result);
}
else{
printk(KERN_INFO "GPIO_TEST: The VSYNC interrupt request FAIL !!! (%d)\n",result);
return result;
}
//HREF
result=request_irq(HREF_irqNumber,(irq_handler_t)HREF_gpio_irq_handler,IRQF_TRIGGER_RISING,"HREF_gpio_handler",NULL);
if(result==0){ //if success
printk(KERN_INFO "GPIO_TEST: The HREF interrupt request result is: %d\n",result);
}
else{
printk(KERN_INFO "GPIO_TEST: The HREF interrupt request FAIL !!! (%d)\n",result);
return result;
}
//PCLK
result=request_irq(PCLK_irqNumber,(irq_handler_t)PCLK_gpio_irq_handler,IRQF_TRIGGER_RISING,"PCLK_gpio_handler",NULL);
if(result==0){// if success
printk(KERN_INFO "GPIO_TEST: The PCLK interrupt request result is: %d\n",result);
}
else{
printk(KERN_INFO "GPIO_TEST: The PCLK interrupt request FAIL !!! (%d)\n",result);
return result;
}
printk(KERN_INFO "MODULE LOADED.... WAITING FOR INTERRUPTION\n");
return result;
}
static void __exit camera_module_test_exit(void){ //cleanup_module(void){
printk(KERN_INFO "EXITING CAMERA_LKM_MODULE_TEST\n");
//unexporting GPIOs
gpio_unexport(VSYNC_gpio_number);
gpio_unexport(HREF_gpio_number);
gpio_unexport(PCLK_gpio_number);
//freeing IRQs
free_irq(VSYNC_irqNumber,NULL);
free_irq(HREF_irqNumber,NULL);
free_irq(PCLK_irqNumber,NULL);
//freeing memory
gpio_free(VSYNC_gpio_number);
gpio_free(HREF_gpio_number);
gpio_free(PCLK_gpio_number);
printk(KERN_INFO "GOODBYE world - MODULE CLOSED\n");
}
static irq_handler_t VSYNC_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs){
printk(KERN_INFO "* VSYNC Interrupt on rising! *\n");
return (irq_handler_t)IRQ_HANDLED;
}
static irq_handler_t HREF_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs){
printk(KERN_INFO "-- HREF interrupt! on rising --\n");
return (irq_handler_t)IRQ_HANDLED;
}
static irq_handler_t PCLK_gpio_irq_handler(unsigned int irq,void *dev_id,struct pt_regs *regs){
printk(KERN_INFO "// PCLK interrupt! on rising //\n");
return (irq_handler_t)IRQ_HANDLED;
}
module_init(camera_module_test_init);
module_exit(camera_module_test_exit);
MODULE_LICENSE("GPL");
I can add that I am using hummingboard gate with available gpios shown in attached image.
hummingboard gate available gpios
Related
I am developing a kernel module for an embedded device, The device core is Toradex iMX6DL.
So I have an IO-Expander of mcp23xxx series on this device and I can work with its GPIOs. I can set them as input/output and get/set their values.
I need to use one of them as an interrupt, this is the part of my code for setting interrupt:
static irqreturn_t r_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
{
printk(KERN_DEBUG "interrupt received (irq: %d)\n", irq);
//do some stuff here
return IRQ_HANDLED;
}
...
if(gpio_request(497, 0)==0)
{
int result;
gpio_direction_input(497);
gpio_set_debounce(497, 100);
gpio_export(497,false);
irqNumber =gpio_to_irq(497); // map your GPIO to an IRQ
printk("irq number : %d\r\n",irqNumber);
result = request_irq(irqNumber, // requested interrupt
(irq_handler_t) r_irq_handler, // pointer to handler function
IRQF_TRIGGER_RISING, // interrupt mode flag
"irqHandler", // used in /proc/interrupts
NULL); // the *dev_id shared interrupt lines, NULL is okay
printk("irq request for pin %d result:%d \r\n",497,result);
if(result == SUCCESS)
printk("irq request for pin %d succeeds\r\n",497);
}
The result of gpio_to_irq() is '-6' and the result of request_irq() is '-22', What should I do to get this GPIO's interrupt?
For one of my projects I'm slightly modifying the Linux serial driver, so I can drive a GPIO pin to 1 right before a Tx session starts and to 0 again after the session ends. I'm doing this by including the gpio header in the driver and calling the appropriate functions:
EDIT:
After the suggestions of #sawdust in the comments the new code looks like this
In Tx start:
static void imx_start_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
gpio_set_value(140, 1);
In Tx stop:
static void imx_stop_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
gpio_set_value(140, 0);
While the GPIO request is being done in the imx_startup:
static int imx_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
int retval, i;
unsigned long flags, temp;
/* Request GPIO #140, used for control flow */
int gpio_num = 140;
const char* label = "f";
if (!gpio_is_valid(gpio_num)){
printk(KERN_INFO "GPIO_RS485: invalid GPIO pin\n");
return -ENODEV;
}
int gpio_req = gpio_request(gpio_num, label);
if(gpio_req != 0){
printk(KERN_INFO "GPIO_RS485: GPIO access request failed with %d\n", gpio_req);
} else {
printk(KERN_INFO "GPIO_RS485: GPIO access request succeeded!\n");
}
And the gpio_free(); is being called in imx_shutdown
static void imx_shutdown(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
unsigned long flags;
gpio_free(140);
However the issue persists.
Another thing is that now I'm getting the following messages in dmesg, which means that the driver is being initialized several times?
EDIT ENDS HERE
The problem with this code is that I can confirm that the pin is correctly being driven to 1, but then it never gets back to 0. Why is this happening and how can I fix this?
Just do some research of ftrace.
TCP echo program is running between two host.
When I shutdown the big switch(echo 0 > /proc/sys/kernel/ftrace_enabled ), my own kprobe module cannot work also. The printk message cannot be seen in the kernel log file. Also, The pkt modify operation failed and the pkt can be received successfully.
It really confused me a lot.
My test kprobe module is here:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/skbuff.h>
#include <linux/inet.h>
/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
.symbol_name = "ip_rcv",
};
/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct sk_buff * skb = (struct sk_buff *)(regs->di);
u16 dst_port;
dst_port = ntohs(*((u16*)(skb->head + skb->transport_header + 2)));
if(dst_port == 50000){ //50000 is the TCP port
printk(KERN_INFO "post handler addr 0x%p skb is 0x%d\n",p->addr, regs->di);
// modify one byte to make TCP checksum wrong and drop the pkt.
*((u8*)(skb->head + skb->network_header +7))=0xab;
}
return 0;
}
/* kprobe post_handler: called after the probed instruction is executed */
static void handler_post(struct kprobe *p, struct pt_regs *regs,
unsigned long flags)
{
//printk(KERN_INFO "post handler addr 0x%p skb is 0x%d\n",p->addr, regs->di);
}
/*
* fault_handler: this is called if an exception is generated for any
* instruction within the pre- or post-handler, or when Kprobes
* single-steps the probed instruction.
*/
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",
p->addr, trapnr);
/* Return 0 because we don't handle the fault. */
return 0;
}
static int __init kprobe_init(void)
{
int ret;
kp.pre_handler = handler_pre;
kp.post_handler = handler_post;
kp.fault_handler = handler_fault;
ret = register_kprobe(&kp);
if (ret < 0) {
printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
return ret;
}
printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);
return 0;
}
static void __exit kprobe_exit(void)
{
unregister_kprobe(&kp);
printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
}
module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");
Question Closed.
Actually in sys/kernel/debug/kprobes/list we can get the list of registered kprobe. And I get this xxxxxxxxxxx k ip_rcv+0x0 [FTRACE], it means that the this kprobe is ftrace-based. ftrace-based kprobe cannot work if disable the ftrace.
I am currently working on a kernel module for a RaspberryPi 3 and am new to this area. This should generate an interrupt on a rising or falling edge. In the corresponding ISR, a time stamp is set and a signal is generated to notify a user application.
I have taken the signaling for the sake of the code.
My goal is now to write the value of the time stamp into a shared memory and the user application can read it out after an incoming signal in order to measure the latency between the interrupt and the signal received in the user application. I have already researched but found no solution. How do I map the virtual kernel address of the allocated memory into the user application and what steps are necessary?
Thanks in advance.
Kernel Code:
/****************************************************************************/
/* Kernelmodul Shared Memory */
/****************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
// kmalloc
#include <linux/slab.h>
// ioremap
#include <asm/io.h>
/****************************************************************************/
/* Define block */
/****************************************************************************/
#define DriverAuthor ""
#define DriverDescription "Shared Memory"
#define InterruptPin 26
#define GPIO_PIN_DEV_STR "PIN"
#define GPIO_PIN_STR "Timestamp"
unsigned int * timerAddr;
unsigned int time = 0;
unsigned int * SHMvirtual = 0;
/****************************************************************************/
/* Module params declaration block */
/****************************************************************************/
static short int gpio_pin = InterruptPin;
/****************************************************************************/
/* Interrupts variables block */
/****************************************************************************/
short int irq_gpio_pin = InterruptPin;
short int irq_enabled = 0; // this is only a flag
/****************************************************************************/
/* IRQ handler */
/****************************************************************************/
static irqreturn_t ISR(int irq, void *dev_id, struct pt_regs *regs) {
unsigned long flags;
// disable hard interrupts (remember them in flag 'flags')
local_irq_save(flags);
time = timerAddr[1];
*SHMvirtual = time;
// restore hard interrupts
local_irq_restore(flags);
return IRQ_HANDLED;
}
/****************************************************************************/
/* This function configures interrupts. */
/****************************************************************************/
void configInterrupts(void) {
if (gpio_request(gpio_pin, GPIO_PIN_STR))
{
printk(KERN_INFO "GPIO request faiure %d\n", gpio_pin);
return;
}
if ( (irq_gpio_pin = gpio_to_irq(gpio_pin)) < 0 )
{
printk(KERN_INFO "GPIO to IRQ mapping faiure %d\n", gpio_pin);
return;
}
printk(KERN_INFO "Mapped int %d\n", irq_gpio_pin);
if (request_irq(irq_gpio_pin, (irq_handler_t ) ISR, (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), GPIO_PIN_STR,
GPIO_PIN_DEV_STR))
{
printk("Interrupt Request failure\n");
return;
}
return;
}
/****************************************************************************/
/* This function releases interrupts. */
/****************************************************************************/
void releaseInterrupt(void) {
free_irq(irq_gpio_pin, GPIO_PIN_DEV_STR);
gpio_free(gpio_pin);
return;
}
/****************************************************************************/
/* Module init / cleanup block. */
/****************************************************************************/
int initModule(void) {
printk(KERN_INFO "Hello\n");
configInterrupts();
timerAddr = ioremap(0x3F003000, 0x20);
SHMvirtual = (unsigned int *)kmalloc(sizeof(time),GFP_USER);
return 0;
}
void cleanupModule(void) {
printk(KERN_INFO "Goodbye\n");
releaseInterrupt();
kfree(SHMvirtual);
return;
}
module_init(initModule);
module_exit(cleanupModule);
/****************************************************************************/
/* Module licensing/description block. */
/****************************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DriverAuthor);
MODULE_DESCRIPTION(DriverDescription);
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.