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

#include <linux/types.h> 
#include <linux/kdev_t.h>
#include <linux/fs.h>   
#include <linux/cdev.h> 
#include <asm/uaccess.h>

#include <linux/gpio.h>

#include <linux/interrupt.h>

#define	GPIO_OUT	20			// GPIO_105
#define	GPIO_IN		21			// GPIO_148

static dev_t gpio_dev;

struct cdev gpio_cdev;

static int gpio_lock = 0;

volatile char gpio_in_value = 0;

static irq_handler_t InterruptHandler( unsigned int irq, struct pt_regs *regs )
{		
	gpio_in_value = gpio_get_value( GPIO_IN );

	printk( KERN_INFO "gpio_dev: %s got GPIO_IN with value %c\n", 
                __func__, gpio_in_value+'0' );

	return (irq_handler_t) IRQ_HANDLED; 
}


int gpio_open(struct inode *inode, struct file *file)
{
    int ret = 0;

    printk( KERN_INFO "gpio_dev: %s\n", __func__ );
    if( gpio_lock > 0 )
    {
	ret = -EBUSY;
    }
    else
        gpio_lock++;

   return( ret );
}

int gpio_close(struct inode *inode, struct file *file)
{
    printk( KERN_INFO "gpio_dev: %s\n", __func__ );
    
    gpio_lock = 0;

    return( 0 );
}


ssize_t gpio_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    char buffer[2];

    printk(KERN_INFO "gpio read (count=%d, offset=%d)\n", (int)count, (int)*f_pos );

    buffer[0] = gpio_in_value;
    buffer[1] = 0;

    copy_to_user( buf, buffer, 1 );

    return 1;
}

ssize_t gpio_write(struct file *filp, const char *buffer, size_t length, loff_t * offset)
{
    int	n = 0;

    while( length )
    {
	if( *buffer == '0' )
	{
	    gpio_set_value( GPIO_OUT, 0 );
	    printk( KERN_INFO "gpio_dev: %s wrote %c to GPIO_OUT\n", __func__, *buffer );
	}
	if( *buffer == '1' )
	{
	    gpio_set_value( GPIO_OUT, 1 );
	    printk( KERN_INFO "gpio_dev: %s wrote %c to GPIO_OUT\n", __func__, *buffer );
	}
	buffer++;
	length--;
	n++;
    }

    return( n );
}


struct file_operations gpio_fops = {
    .owner = THIS_MODULE,
    .read = gpio_read,
    .write = gpio_write,
    .open = gpio_open,
    .release = gpio_close,
};

static int __init gpio_module_init(void)
{
    char buffer[64];
    int	ret = 0;

    printk(KERN_INFO "Loading gpio_module\n");

    alloc_chrdev_region(&gpio_dev, 0, 1, "gpio_dev");
    printk(KERN_INFO "%s\n", format_dev_t(buffer, gpio_dev));

    cdev_init(&gpio_cdev, &gpio_fops);
    gpio_cdev.owner = THIS_MODULE;
    cdev_add(&gpio_cdev, gpio_dev, 1);

    if( gpio_request( GPIO_OUT, "gpio_dev" ) )
    {
	printk( KERN_INFO "gpio_dev: %s unable to get GPIO_OUT\n", __func__ );
	ret = -EBUSY;
	goto Done;
    }

    if( gpio_request( GPIO_IN, "gpio_dev" ) )
    {
	printk( KERN_INFO "gpio_dev: %s unable to get GPIO_IN\n", __func__ );
	ret = -EBUSY;
	goto Done;
    }

    if( gpio_direction_output( GPIO_OUT, 0 ) < 0 )
    {
	printk( KERN_INFO "gpio_dev: %s unable to set GPIO_OUT as output\n", __func__ );
	ret = -EBUSY;
	goto Done;
    }

    if( gpio_direction_input( GPIO_IN ) < 0 )
    {
	printk( KERN_INFO "gpio_dev: %s unable to set GPIO_IN as input\n", __func__ );
	ret = -EBUSY;
	goto Done;
    }

    if( request_irq( gpio_to_irq( GPIO_IN ), (irq_handler_t) InterruptHandler, 
	 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "gpio_dev", NULL ) < 0 )
    {
	printk( KERN_INFO "gpio_dev: %s unable to register gpio irq for GPIO_IN\n",
               __func__ );
		
       ret = -EBUSY;
       goto Done;
    }

Done:
    return ret;
}

static void __exit gpio_module_cleanup(void)
{
    printk(KERN_INFO "Cleaning-up gpio_dev.\n");

    gpio_free( GPIO_OUT );
    gpio_free( GPIO_IN );

    free_irq( gpio_to_irq( GPIO_IN ), NULL );

    gpio_lock = 0;

    cdev_del(&gpio_cdev);
    unregister_chrdev_region(gpio_dev, 1);
}

module_init(gpio_module_init);
module_exit(gpio_module_cleanup);

MODULE_AUTHOR("Your Name");
MODULE_LICENSE("GPL");


This page: Created:Wed Jan 31 16:18:09 2024
From: 17389.tmp/gpio.c

Verilog converted to html by v2html 7.30.1.3 v2html 7.30.1.3 (written by Costas Calamvokis).Help