Wednesday, May 1, 2013

Raspberry Pi interrupt to signal conversion C source code, kernel module


This code is from project: Raspberry pi interrupt to signal conversion, kernel to user space

m_gpioSignal.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/interrupt.h>
#include <linux/gpio.h>

#include <asm/uaccess.h>
#include <linux/fs.h>

#include <linux/signal.h>
#include <linux/sched.h>


#define DRIVER_AUTHOR      "Igor <hardware.coder@gmail.com>"
#define DRIVER_DESC        "Test sending signal triggered by gpio."

#define DEVICE_NAME        "m_gpioSignal"
#define READ_BUFF_LEN      6

#define DEFAULT_GPIO_PIN   17
#define GPIO_PIN_DEV_STR   "pin"
#define GPIO_PIN_STR       "Signal trigger gpio pin."

#define DEFAULT_SIGNAL     34


/****************************************************************************/
/* Module params declaration block                                          */
/****************************************************************************/
static short int gpio_pin = DEFAULT_GPIO_PIN;


/****************************************************************************/
/* Interrupts variables block                                               */
/****************************************************************************/
short int irq_gpio_pin   = DEFAULT_GPIO_PIN;
short int irq_enabled    = 0;    // this is only a flag


/****************************************************************************/
/* Function variables block                                                 */
/****************************************************************************/
pid_t send_to_pid        = 0;    // here will be pid of process to which
                                 // signal will be send
short int signal_to_pid  = DEFAULT_SIGNAL;


/****************************************************************************/
/* Device variables block                                                   */
/****************************************************************************/
static int     major_device_num;
static int     device_open_counter = 0;

static int     r_open(struct inode *, struct file *);
static int     r_release(struct inode *, struct file *);

static ssize_t r_write(struct file *,  const char *, size_t, loff_t *);

static struct file_operations fops = {
   .write   = r_write,
   .open    = r_open,
   .release = r_release
};


/****************************************************************************/
/* Device funtions                                                          */
/****************************************************************************/
static int r_open(struct inode *inode, struct file *file) {

   if (device_open_counter)
      return -EBUSY;

   device_open_counter++;
   try_module_get(THIS_MODULE);

//    printk(KERN_INFO "Dev open\n");

   return 0;
}


static ssize_t r_write(struct file *f, const char *buff_in, size_t data_len,
                       loff_t * offset) {

   char readBuff[READ_BUFF_LEN];

   if (data_len > READ_BUFF_LEN) {
      printk(KERN_INFO "Read error, buffer overflow\n");
      return -EINVAL;
   }

   copy_from_user(readBuff, buff_in, data_len);    // copy char data from
                                                   // /dev/m_gpioSignal

   rcu_read_unlock();   // must be used, otherwise code will loop

   if (sscanf(readBuff, "%d", &send_to_pid)  == 1) {
      printk(KERN_INFO "send_to_pid set: %d\n", send_to_pid);

      irq_enabled = 1;     // enable interrupt processing flag

   } else {
      printk(KERN_INFO "Read error.\n");
   }

   return data_len;
}


static int r_release(struct inode *inode, struct file *file) {
   device_open_counter--;

   module_put(THIS_MODULE);

//    printk(KERN_INFO "Dev closed \n");

   return 0;
}


/****************************************************************************/
/* Module params binding block.                                             */
/****************************************************************************/
module_param(gpio_pin, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(gpio_pin, "Pin which is connected to button");

module_param(signal_to_pid, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(signal_to_pid, "Signal to send");


/****************************************************************************/
/* IRQ handler                                                              */
/****************************************************************************/
static irqreturn_t r_irq_handler(int irq, void *dev_id, struct pt_regs *regs) {


   struct task_struct *task_from_pid;

   if (irq_enabled == 0 )  // if interrupt flag is disabled, return
      return IRQ_HANDLED;

   irq_enabled = 0;

   // get the task from pid for funcion send_sig_info
   if ( (task_from_pid = pid_task(find_vpid(send_to_pid),
                                  PIDTYPE_PID)) == NULL ) {
      printk(KERN_INFO "Can't find task assocaied with pid: %d\n", send_to_pid);
      return IRQ_HANDLED;
   }

   // send signal (without info struct) to pid descriped by task
   if (send_sig_info(signal_to_pid, SEND_SIG_FORCED, task_from_pid) < 0 ) {
      printk(KERN_INFO "Signal not send\n");
   } else {
      printk(KERN_INFO "Signal %d was send to pid %d\n",
             signal_to_pid, send_to_pid);
   }


   return IRQ_HANDLED;
}


/****************************************************************************/
/* This function configures interrupts.                                     */
/****************************************************************************/
void r_int_config(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 ) r_irq_handler,
                   IRQF_TRIGGER_FALLING,
                   GPIO_PIN_STR,
                   GPIO_PIN_DEV_STR)) {
      printk("Irq Request failure\n");
      return;
   }

   printk(KERN_INFO "Info: signal_to_pid is %d, gpio_pin is %d\n",
          signal_to_pid, gpio_pin);

   return;
}


/****************************************************************************/
/* This function releases interrupts.                                       */
/****************************************************************************/
void r_int_release(void) {

   free_irq(irq_gpio_pin, GPIO_PIN_DEV_STR);
   gpio_free(gpio_pin);

   return;
}


/****************************************************************************/
/* Module init / cleanup block.                                             */
/****************************************************************************/
int r_init(void) {

   printk(KERN_INFO "Hello\n");
   r_int_config();

   if ((major_device_num = register_chrdev(0, DEVICE_NAME, &fops)) < 0 ) {
     printk(KERN_ALERT "Registering char device failed with %d\n",
            major_device_num);
     return major_device_num;
   }

   printk(KERN_INFO "'mknod /dev/%s c %d 0'\n", DEVICE_NAME,
         major_device_num);

   return 0;
}


void r_cleanup(void) {
   printk(KERN_INFO "Goodbye\n");
   r_int_release();

   unregister_chrdev(major_device_num, DEVICE_NAME);

   return;
}


module_init(r_init);
module_exit(r_cleanup);


/****************************************************************************/
/* Module licensing/description block.                                      */
/****************************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);


/****************************************************************************/
/* Module function blocks.                                                  */
/****************************************************************************/

Makefile

# my optional module name
MODULE=m_gpioSignal

# this two variables, depends where you have you raspberry kernel source and tools installed
CCPREFIX=/opt/raspberry_pi-kernel/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
KERNEL_SRC=/opt/raspberry_pi-kernel/linux


obj-m += ${MODULE}.o

module_upload=${MODULE}.ko

all: clean compile

compile:
 make ARCH=arm CROSS_COMPILE=${CCPREFIX} -C ${KERNEL_SRC} M=$(PWD) modules

clean:
 make -C ${KERNEL_SRC} M=$(PWD) clean

# this just copies a file to raspberry (rb is an alias in /etc/hosts as ip of my raspberry pi)
# install is depend to 'all' so after code change, you must only do 'make install'
# code will be compiled and send to your raspberry pi
install: all
 scp ${module_upload} pi@rb:progs/cpp/gpioSignal

# this invokes my test script which load module and do a small test
restart:
 ssh pi@rb 'progs/cpp/gpioSignal/mod_test' 

# show information about module
info:
 modinfo  ${module_upload}

15 comments:

  1. i dont understood u r makefile...how u r written makefile?r u did cross compile or direct installation on raspberry pi?how u wrote makefile?Please Tell me how wrote makefile...r u download the raspberry pi kernel? and place into opt folder ryt?


    Thanks&Regards,
    K.Arungopal

    ReplyDelete
  2. Hi is any method to wrote makre file using buildroot?Please Send link how to build cross compile the kernel modules for raspberry pi using cross tool ng?

    Thanks&Regards,
    K.Arungopal

    ReplyDelete
    Replies
    1. Hi,

      Yes I'm using cross-compile, you can find it here: http://bchavez.bitarmory.com/archive/2013/01/16/compiling-kernel-modules-for-raspberry-pi.aspx

      One difference is I put raspberry pi kernel in /opt instead of /home/

      I'll add some comments to Makefile above, you have right that now is confusing.

      Regards,
      Igor.

      Delete
  3. Hi Iam copy and paste u r driver code...and iam copy and paste u r makefile....iam also cross compile the raspberry pi..iam create a one folder in the opt that is rpi in that iam place two folders that is tools-master and raspberrry pi kernel...iam change u r makefile that is change only ccPREFIX and KERNEL_SRC to my path.....

    When iam type the make it shows...
    make: *** /home/arun/opt/rpi/linux-rpi-3.2.27: No such file or directory. Stop.
    make: *** [clean] Error 2....



    My makefile is



    # my optional module name
    MODULE=m_gpioSignal

    # this two variables, depends where you have you raspberry kernel source and tools installed
    CCPREFIX=/home/arun/opt/rpi/tools-master/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
    KERNEL_SRC=/home/arun/opt/rpi/linux-rpi-3.2.27


    obj-m += project.o

    module_upload=project.ko

    all: clean compile

    compile:
    make ARCH=arm CROSS_COMPILE=${CCPREFIX} -C ${KERNEL_SRC} M=$(PWD) modules

    clean:
    make -C ${KERNEL_SRC} M=$(PWD) clean

    # this just copies a file to raspberry (rb is an alias in /etc/hosts as ip of my raspberry pi)
    # install is depend to 'all' so after code change, you must only do 'make install'
    # code will be compiled and send to your raspberry pi
    install: all
    scp ${module_upload} pi@rb:progs/cpp/gpioSignal

    # this invokes my test script which load module and do a small test
    restart:
    ssh pi@rb 'progs/cpp/gpioSignal/mod_test'

    # show information about module
    info:
    modinfo ${module_upload}





    What is the problem in the makefile?Please clarify my dought?

    Thanks&Regards,
    K.Arungopal
    ~



    ReplyDelete
    Replies
    1. Hi,

      Post output from ls /home/arun/opt/rpi/linux-rpi-3.2.27

      Regards,
      Igor.

      Delete
  4. Hi Sir,
    i did not get you?Post output means?i given paths are correct or not sir?iam download the raspberry kernel and tools master and and place in the opt folder and export that path...that is?iam done anything for this for installation of cross compilation....Is any mistakes in make file?Please clarify me...


    thanks&Regards,
    K.Arungopal

    ReplyDelete
    Replies
    1. Hi,

      My Makefile is ok, on my host everything works fine.

      Please try again with this:

      1. Ignore my makefile.
      2. Once again follow http://bchavez.bitarmory.com/archive/2013/01/16/compiling-kernel-modules-for-raspberry-pi.aspx
      3. Be sure that you've created separate directory and put there my code. This step was described in tutorial from link above.
      4. At point 2 (of description from link) change line:
      obj-m += rpi-pwm.o
      to
      obj-m += project.o
      (like you've done in my Makefile)

      I followed tutorial from link I've pasted, and everything is working. I can't help you with this, because I don't have access to your host.

      I could help you with my code, but cross-compilation is a basic task, and I gave you link with step-by-step tutorial you should deal with it yourself.

      Regards,
      Igor.

      Delete
  5. Hi Sir,
    iam did cross compile for raspberry pi for c and cpp programes...iam not cross compile raspberry pi for modules..That is my problem..i follow u r link that is cross compilation of raspberry pi..mainly problem is when iam type make ARCH=arm CROSS_COMPILE=${CCPREFIX} oldconfig and make ARCH=arm CROSS_COMPILE=${CCPREFIX}.....Lot of options is coming? how to select those options?i mean default settings is ok or any change is neccessary?if neccessary what changes iam did for that? iam did many times if iam place default setings iam not get the "Module.symvers"...when iam compile the programs usinmg make it shows

    Module.symvers is missing; modules will have no dependencies and modversions....


    what change is iam do for two commands?


    thanks&Regards,
    K.Arungopal

    ReplyDelete
    Replies
    1. Hi,

      Please paste output from command executed on raspberry pi:

      uname -r

      and send me config.gz from your raspberry (my e-mail is in "Rules" above)

      /proc/config.gz

      I'll compile it locally on my host and check what is missing, then I post you what to do. Today I don't have time for this, but tomorrow I could find a minute.

      Regards,
      Igor.

      Delete
  6. hi Sir,
    in the rules form i did not get u r mail..u r mail id is not there sir.

    Please contact:hadware.coder at google dot com...thats it in that i have this only..Please send u r mail id....my mail id is kondaveetiarungopal@gmail.com....

    thanks&regards,
    K.Arungopal

    ReplyDelete
    Replies
    1. Hi,

      I've send you my email on your address. Double check if you had download kernel version which match the one from command 'uname -r' (executed on raspberry pi).

      These questions during 'make ...' may suggest that your /proc/config.gz is in different version than downloaded kernel.

      If 'uname -r' and downloaded kernel version differs, than just download right kernel version and start all over.

      Regards,
      Igor.

      Delete
  7. Hi Sir,
    u r mail id is not working...mail is not sent it shows failed to send...i got u r mail id is
    http://morethanuser.blogspot.com u said this is u r mail id...but when u r give reply to me in posts....i got mails..when iam give reply to that mails it is send successfully...r u got my mails sir?when iam giving reply to u...ok sir...now iam follow what u r saying that is config.gz file kernel version and download kernel version bothare same ryt?ok sir...i will do that..And one more thing when iam type make ARCH=arm CROSS_COMPILE=${CCPREFIX} oldconfig
    it shows lot of options to select..how to select those options?this is one dought Please clarify this...

    Thanks&regards,
    K.Arungopal

    ReplyDelete
    Replies
    1. Hi,

      I think, when your /proc/config.gz will be the same as downloaded kernel version, you won't have to answer on this questions because they will be answered in /proc/config.gz

      Regards,
      Igor.

      Delete
  8. hello is this code for reading gpio voltage???

    ReplyDelete
    Replies
    1. Hi,
      Nope. This code sends signal 34(default) to process, which PID was given in /dev/m_gioSignal.
      What do you mean by "reading gpio voltage", you want Analog to Digital Converter or only check for HIGH/LOW voltage ?
      If you want ADC, use something like AD7992 and connect it via I2C bus. If you want only check for HIGH/LOW state, use some logic gate, for eg. CD4093B - NAND gate with Schmitt Trigger, and then adjust trigger voltage level by some resistors, and you're done :)

      Delete