• Uncategorized

About linux : Kernel-Module-using-PI2—control-one-led-ERROR

Question Detail

I’m trying to make a kernel module, using a Raspberry PI 2, to simply control a led as part of a school project.

“echo 0 > /dev/gpio-driver” -> Led OFF

“echo 1 > /dev/gpio-driver” -> Led On

However, my code isn’t 100% correct, because I load the module and the led is always on, when I do
“echo 0 > /dev/gpio-driver” the led turn off but after a few seconds turn on again.

I don’t know where the error is so I posted what I have so far.

Thanks a lot,
Eddy

/*
 * Kernel modules for Raspberry PI
 * Creation/Analysis of kernel modules for Raspberry PI
 */

#include <linux/module.h> 
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/gpio.h>

MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("");
MODULE_DESCRIPTION ("Simple kernel module to controle an LED");

#define DEVICE_NAME "gpio-chrdev"
#define DEVICE_FILE_NAME "gpio-file"
#define CLASS "gpio-project"

#define MAX_FILE_SIZE 3
static int size; //Initialize to 0 in module_init
static char data[MAX_FILE_SIZE];

static int __init gpio_driver_init (void);
static void __exit gpio_driver_exit (void);
static int gpio_driver_open (struct inode *inode, struct file *filp);
static int gpio_driver_release (struct inode *inode, struct file *filp);
static ssize_t gpio_driver_read (struct file *filp, char __user * buf,
        size_t count, loff_t * offset);
static ssize_t gpio_driver_write (struct file *filp, const char __user * buf,
        size_t count, loff_t * offset);


static dev_t devnr;
//static struct device *device;
static struct cdev LED_cdev;
/* Notify udev from the module - first create a virtual device class */
static struct class *gpio_class;
static int deviceopen = 0;

module_init(gpio_driver_init);
module_exit(gpio_driver_exit);

static struct file_operations LED_fops = {
    .owner =    THIS_MODULE,
    .read =     gpio_driver_read,
    .write =    gpio_driver_write,
    .open =     gpio_driver_open,
    .release =  gpio_driver_release,
};

/* This function is called when this module is loaded into the kernel  */

static int __init gpio_driver_init(void){

    /* Device file creation */

    /* Alocate device number */
    /* The major number will be chosen dynamically and returned in dev
     * Returns zero or a negative erro code */

    if(alloc_chrdev_region(&devnr, 0, 1, DEVICE_FILE_NAME) < 0) {
        printk("Device class can't be created\n");
        return -1;
    }


    /* Create device class  */
    /* Create a new class for this device. It will be visible in /sys/class  */

    if ((gpio_class = class_create(THIS_MODULE, CLASS)) == NULL) {
        printk("Device class can't be created\n");
        goto classerror;
    }


    /* Inicialize device*/

    cdev_init (&LED_cdev, &LED_fops);

    /* Activate the device  */

    if ((cdev_add (&LED_cdev, devnr, 1)) == -1){
        printk("Unable to register the device\n");
        goto validerror;
    }

    /* Create device file  */
    /* Device info can be viewd under /sys/class/arcom-project */

    if ((device_create (gpio_class, NULL, devnr, NULL, DEVICE_NAME)) == NULL){
        printk("Can't create device file\n");
        goto fileerror;
    }

    /*
     * GPIO configurations
     * ********************/

    /* Check if GPIO is valid */

    if(gpio_is_valid(4) == false){
        printk("GPIO is not valid\n");
        goto validerror;
    }

    /* GPIO 4 Request */

    if(gpio_request(4, "gpio-4") < 0 ){
        printk("Can't request GPIO 4\n");
        goto gpio4requesterror;
    }

    /* Configure GPIO as output*/

    gpio_direction_output(4, 0);

    //gpio_export(4, false);

    return 0;

validerror: 
    device_destroy(gpio_class, devnr);

gpio4requesterror: 
    gpio_free(4);

fileerror:
    class_destroy(gpio_class);

classerror: 
    unregister_chrdev_region(devnr, 1);
    return -1;

}

static int gpio_driver_open(struct inode *inode, struct file *filp)
{
    if (deviceopen)
    {
        printk(KERN_WARNING "Already open\n");
        return -EBUSY;
    }
    try_module_get(THIS_MODULE);
    deviceopen = 1;
    return 0;
}

int gpio_driver_release(struct inode *inode, struct file *filp)
{
    deviceopen = 0;
    module_put(THIS_MODULE);
    return 0;
}

/* Read data out of the buffer */

static ssize_t gpio_driver_read(struct file *filp, char __user *buf, size_t count, loff_t * offset)
{

    int i;
    int last = *offset + count;

    if (last > size)
    {
        last = size;
    }
    i = last - *offset;
    if (i == 0)
    {
        return 0;
    }

    if (copy_to_user (buf, data + *offset, i))
    {
        return -EFAULT;
    }
    return i;
}

/* Write data to buffer */

static ssize_t gpio_driver_write(struct file *filp, const char __user *buf, size_t count, loff_t * offset)
{
    int i, n;
    int last = *offset + count;
    if (last > MAX_FILE_SIZE)
        last = MAX_FILE_SIZE;
    i = last - *offset;
    n = copy_from_user (data + *offset, buf, i);

    if (n != 0)
    {
        pr_warn ("Could not copy %d bytes\n", n);
        return -EFAULT;
    }
    *offset += i;
    if (size < *offset)     //keep data from previous accesses
        size = *offset;


    /* Setting the LED - 0 or 1*/
    if (data[0] == '0'){
        gpio_set_value(4,0);
    }
    else if (data[0] == '1'){
        gpio_set_value(4,1);
    }
    else {
        printk("Invalid input\n");
    }

    return i;
}

/*
   static void my_timer_func(struct timer_list *unused){
   led_status = ~led_status;
   outb(led_status, 0x378);
   my_timer.expires += blink_delay;
   add_timer(&my_timer);
   }
   */
void gpio_driver_exit(void){
    //gpio_unexport(4);
    gpio_free(4);
    cdev_del(&LED_cdev);
    device_destroy(gpio_class, devnr);
    class_destroy(gpio_class);
    unregister_chrdev_region(devnr, 1);
    printk("Live long and prosper\n");
}


EDIT:
Hello,
I’ve redone the program, also the module w1-gpio was loaded and messing with the module I tried to implement, so after the changes in the code and remove the module everything worked fine

/*
 * Kernel modules for Raspberry PI
 * Creation/Analysis of kernel modules for Raspberry PI
 */

#include <linux/module.h> 
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/gpio.h>

MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("");
MODULE_DESCRIPTION ("Simple kernel module to controle an LED");

#define MAX_FILE_SIZE 3
static int size; //Initialize to 0 in module_init
//static char data[MAX_FILE_SIZE];

static int __init gpio_driver_init (void);
static void __exit gpio_driver_exit (void);
static int gpio_driver_open (struct inode *inode, struct file *filp);
static int gpio_driver_release (struct inode *inode, struct file *filp);
static ssize_t gpio_driver_read (struct file *filp, char __user * buf,
        size_t count, loff_t * offset);
static ssize_t gpio_driver_write (struct file *filp, const char __user * buf,
        size_t count, loff_t * offset);


static dev_t devnr;
static struct cdev LED_cdev;
/* Notify udev from the module - first create a virtual device class */
static struct class *gpio_class;
static int deviceopen = 0;

module_init(gpio_driver_init);
module_exit(gpio_driver_exit);

static struct file_operations LED_fops = {
    .owner =    THIS_MODULE,
    .read =     gpio_driver_read,
    .write =    gpio_driver_write,
    .open =     gpio_driver_open,
    .release =  gpio_driver_release,
};

/* This function is called when this module is loaded into the kernel  */

static int __init gpio_driver_init(void){

    /* Device file creation */

    /* Alocate device number */
    /* The major number will be chosen dynamically and returned in dev
     * Returns zero or a negative erro code */
    if((alloc_chrdev_region(&devnr, 0, 1, "project_dev")) < 0) {
        printk("Device class can't be created\n");
        goto err_alloc;
    }

    /* Create cdev structure */
    cdev_init (&LED_cdev, &LED_fops);

    /* Add character device to the system  */
    if ((cdev_add (&LED_cdev, devnr, 1)) == -1){
        printk("Unable to register the device\n");
        device_destroy(gpio_class, devnr);
    }

    /* Create device class  */
    /* Create a new class for this device. It will be visible in /sys/class  */
    if ((gpio_class = class_create(THIS_MODULE, "project_class")) == NULL) {
        printk("Device class can't be created\n");
        goto err_class;
    }

    /* Create device file  */
    /* Device info can be viewd under /sys/class/arcom-project */
    if ((device_create (gpio_class, NULL, devnr, NULL, "project_device")) == NULL){
        printk("Can't create device file\n");
        goto err_device;
    }
    size = 0;

    /* GPIO configuration */

    /* Checking if GPIO is valid */
    if(gpio_is_valid(4) == false){
        printk("GPIO is no valid\n");
        goto err_device;
    }

    /* Requesting the GPIO */
    if(gpio_request(4, "gpio-4") < 0){
        printk("GPIO not requested\n");
        goto err_gpio;
    }

    /* Configure GPIO as output */
    if(gpio_direction_output(4,0)){
        printk("Can not set GPIO to output\n");
        goto err_gpio;
    }
    
    /* For debugging purposes we can export the GPIO which is allocated 
     * usig the gpio_request - /sys/class/gpio/gpio* */
    gpio_export(4, false);
    
    printk("Sao 4.30 da manha... e eu ainda aqui!\n");

    return 0;

err_gpio:
    gpio_free(4);
err_device:
    device_destroy (gpio_class, devnr);
err_class:
    class_destroy(gpio_class);
err_alloc:
    unregister_chrdev_region(devnr, 1);

    return -1;
}

static int gpio_driver_open(struct inode *inode, struct file *filp)
{
    if (deviceopen)
    {
        printk(KERN_WARNING "Already open\n");
        return -EBUSY;
    }
    try_module_get(THIS_MODULE);
    deviceopen = 1;
    return 0;
}

int gpio_driver_release(struct inode *inode, struct file *filp)
{
    deviceopen = 0;
    module_put(THIS_MODULE);
    return 0;
}

/* Read data out of the buffer */

static ssize_t gpio_driver_read(struct file *filp, char __user *buf, size_t count, loff_t * offset)
{

    uint8_t gpio_value = 0;
    int i;
    int last = *offset + count;

    /* Read GPIO value */
    gpio_value = gpio_get_value(4);

    if (last > size)
    {
        last = size;
    }
    i = last - *offset;
    if (i == 0)
    {
        return 0;
    }

    if (copy_to_user (buf, &gpio_value + *offset, i)) //VERIFICAR
    {
        return -EFAULT;
    }
    return i;
}

/* Write data to buffer */

static ssize_t gpio_driver_write(struct file *filp, const char __user *buf, size_t count, loff_t * offset)
{
    char gpio_read;
    int i, n;
    int last = *offset + count;
    if (last > MAX_FILE_SIZE)
        last = MAX_FILE_SIZE;
    i = last - *offset;
    n = copy_from_user (&gpio_read + *offset, buf, i);

    if (n != 0)
    {
        pr_warn ("Could not copy %d bytes\n", n);
        return -EFAULT;
    }
    *offset += i;
    if (size < *offset)     //keep data from previous accesses
        size = *offset;


    /* Setting the LED - 0 or 1*/
    if (n == '0'){
        gpio_set_value(4,0);
    }
    else if (n == '1'){
        gpio_set_value(4,1);
    }
    else {
        printk("Invalid input\n");
    }

    return i;
}

/*
   static void my_timer_func(struct timer_list *unused){
   led_status = ~led_status;
   outb(led_status, 0x378);
   my_timer.expires += blink_delay;
   add_timer(&my_timer);
   }
   */
void gpio_driver_exit(void){
    //gpio_unexport(4);
    gpio_free(4);
    device_destroy(gpio_class, devnr);
    class_destroy(gpio_class);
    cdev_del(&LED_cdev);
    unregister_chrdev_region(devnr, 1);
    printk("Live long and prosper\n");
}

Question Answer

No answer for now.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.