Last active
June 28, 2022 05:32
-
-
Save gnitnaw/b116f358fa688897fe00 to your computer and use it in GitHub Desktop.
module to control 3 LED
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* kernel module for LED | |
* | |
* Author: | |
* Wan-Ting CHEN (wanting@gmail.com) | |
* | |
* This software is licensed under the terms of the GNU General Public | |
* License version 2, as published by the Free Software Foundation, and | |
* may be copied, distributed, and modified under those terms. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
*/ | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/fs.h> // file_operations | |
#include <linux/cdev.h> // Char Device Registration | |
#include <linux/gpio.h> // gpio control | |
#include <linux/delay.h> // mdelay | |
#include <linux/device.h> // class_create | |
#include <linux/types.h> // dev_t | |
#include <asm/uaccess.h> // copy_from_user | |
#define LED_DRIVER_NAME "LED" | |
#define BUF_SIZE 5 | |
static dev_t driverno ; //Default driver number | |
static struct cdev *gpio_cdev; | |
static struct class *gpio_class; | |
static struct gpio leds[] = { | |
{ 2, GPIOF_OUT_INIT_LOW, "LED_0" }, | |
{ 3, GPIOF_OUT_INIT_LOW, "LED_1" }, | |
{ 4, GPIOF_OUT_INIT_LOW, "LED_2" }, | |
}; | |
static int gpio0 = 2; | |
static int gpio1 = 3; | |
static int gpio2 = 4; | |
// Command line paramaters for gpio pin and driver major number | |
module_param(gpio0, int, S_IRUGO); | |
MODULE_PARM_DESC(gpio0, "GPIO-0 pin to use"); | |
module_param(gpio1, int, S_IRUGO); | |
MODULE_PARM_DESC(gpio1, "GPIO-1 pin to use"); | |
module_param(gpio2, int, S_IRUGO); | |
MODULE_PARM_DESC(gpio2, "GPIO-2 pin to use"); | |
// Forward declarations | |
static ssize_t write_LED( struct file *, const char *,size_t,loff_t *); | |
//Operations that can be performed on the device | |
static struct file_operations fops = { | |
.owner = THIS_MODULE, | |
.write = write_LED | |
}; | |
static ssize_t write_LED( struct file *filp, const char *buf,size_t count,loff_t *f_pos){ | |
char kbuf[BUF_SIZE]; | |
unsigned int len=1, gpio; | |
gpio = iminor(filp->f_path.dentry->d_inode); | |
printk(KERN_INFO LED_DRIVER_NAME " GPIO: LED_%d is modified. \n", gpio); | |
len = count < BUF_SIZE ? count-1 : BUF_SIZE-1; | |
if(copy_from_user(kbuf, buf, len) != 0) return -EFAULT; | |
kbuf[len] = '\0'; | |
printk(KERN_INFO LED_DRIVER_NAME " Request from user: %s\n", kbuf); | |
if (strcmp(kbuf, "1") == 0) { | |
printk(KERN_ALERT LED_DRIVER_NAME " LED_%d switch On \n", gpio); | |
gpio_set_value(leds[gpio].gpio, 1); | |
} else if (strcmp(kbuf, "0") == 0) { | |
printk(KERN_ALERT LED_DRIVER_NAME " LED_%d switch Off \n", gpio); | |
gpio_set_value(leds[gpio].gpio, 0); | |
} | |
msleep(100); | |
return count; | |
} | |
static void blink(void) | |
{ | |
int i; | |
printk(KERN_INFO LED_DRIVER_NAME " %s\n", __func__); | |
for(i = 0; i < ARRAY_SIZE(leds); i++) { | |
if(i - 1 >= 0) { | |
gpio_set_value(leds[i - 1].gpio, 0); | |
} | |
gpio_set_value(leds[i].gpio, 1); | |
msleep(500); | |
} | |
gpio_set_value(leds[i - 1].gpio, 0); | |
printk(KERN_INFO LED_DRIVER_NAME " blink ended\n"); | |
} | |
static void modify_gpio(void) { | |
int i; | |
leds[0].gpio = gpio0; | |
leds[1].gpio = gpio1; | |
leds[2].gpio = gpio2; | |
for (i=0; i<ARRAY_SIZE(leds); ++i) { | |
printk(KERN_INFO LED_DRIVER_NAME " Set %s to GPIO %i \n", leds[i].label, leds[i].gpio); | |
} | |
} | |
static int __init LED_init_module(void) | |
{ | |
int ret, i; | |
// Set gpio according to the parameters you give | |
printk(KERN_INFO LED_DRIVER_NAME " %s\n", __func__); | |
modify_gpio(); | |
printk(KERN_INFO LED_DRIVER_NAME " gpio_request_array \n"); | |
ret = gpio_request_array(leds, ARRAY_SIZE(leds)); | |
if(ret < 0) | |
{ | |
printk(KERN_ERR LED_DRIVER_NAME " Unable to request GPIOs: %d\n", ret); | |
goto exit_gpio_request; | |
} | |
// Get driver number | |
printk(KERN_INFO LED_DRIVER_NAME " alloc_chrdev_region \n"); | |
ret=alloc_chrdev_region(&driverno,0,ARRAY_SIZE(leds),LED_DRIVER_NAME); | |
if (ret) { | |
printk(KERN_EMERG LED_DRIVER_NAME " alloc_chrdev_region failed\n"); | |
goto exit_gpio_request; | |
} | |
printk(KERN_INFO LED_DRIVER_NAME " DRIVER No. of %s is %d\n", LED_DRIVER_NAME, MAJOR(driverno)); | |
printk(KERN_INFO LED_DRIVER_NAME " cdev_alloc\n"); | |
gpio_cdev = cdev_alloc(); | |
if(gpio_cdev == NULL) | |
{ | |
printk(KERN_EMERG LED_DRIVER_NAME " Cannot alloc cdev\n"); | |
ret = -ENOMEM; | |
goto exit_unregister_chrdev; | |
} | |
printk(KERN_INFO LED_DRIVER_NAME " cdev_init\n"); | |
cdev_init(gpio_cdev,&fops); | |
gpio_cdev->owner=THIS_MODULE; | |
printk(KERN_INFO LED_DRIVER_NAME " cdev_add\n"); | |
ret=cdev_add(gpio_cdev,driverno,ARRAY_SIZE(leds)); | |
if (ret) | |
{ | |
printk(KERN_EMERG LED_DRIVER_NAME " cdev_add failed!\n"); | |
goto exit_cdev; | |
} | |
printk(KERN_INFO LED_DRIVER_NAME " Play blink\n"); | |
blink(); | |
printk(KERN_INFO LED_DRIVER_NAME " Create class \n"); | |
gpio_class = class_create(THIS_MODULE, LED_DRIVER_NAME); | |
if (IS_ERR(gpio_class)) | |
{ | |
printk(KERN_ERR LED_DRIVER_NAME " class_create failed\n"); | |
ret = PTR_ERR(gpio_class); | |
goto exit_cdev; | |
} | |
printk(KERN_INFO LED_DRIVER_NAME " Create device \n"); | |
for (i=0; i<ARRAY_SIZE(leds); ++i) { | |
if (device_create(gpio_class,NULL, MKDEV(MAJOR(driverno), MINOR(driverno)+i), NULL,leds[i].label)==NULL) { | |
printk(KERN_ERR LED_DRIVER_NAME " device_create failed\n"); | |
ret = -1; | |
goto exit_cdev; | |
} | |
} | |
return 0; | |
exit_cdev: | |
cdev_del(gpio_cdev); | |
exit_unregister_chrdev: | |
unregister_chrdev_region(driverno, ARRAY_SIZE(leds)); | |
exit_gpio_request: | |
gpio_free_array(leds, ARRAY_SIZE(leds)); | |
return ret; | |
} | |
/* | |
* Module exit function | |
*/ | |
static void __exit LED_exit_module(void) | |
{ | |
int i; | |
printk(KERN_INFO LED_DRIVER_NAME " %s\n", __func__); | |
// turn all off | |
for(i = 0; i < ARRAY_SIZE(leds); i++) { | |
gpio_set_value(leds[i].gpio, 0); | |
device_destroy(gpio_class, MKDEV(MAJOR(driverno), MINOR(driverno) + i)); | |
} | |
class_destroy(gpio_class); | |
cdev_del(gpio_cdev); | |
unregister_chrdev_region(driverno, ARRAY_SIZE(leds)); | |
gpio_free_array(leds, ARRAY_SIZE(leds)); | |
} | |
MODULE_LICENSE("GPL"); | |
MODULE_AUTHOR("Wan-Ting CHEN"); | |
MODULE_DESCRIPTION("LED Kernel module"); | |
module_init(LED_init_module); | |
module_exit(LED_exit_module); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
obj-m += LED.o | |
EXTRA_CFLAGS += -I$(PWD) | |
all: | |
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules | |
clean: | |
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Name : output_test.c | |
* Author : Vu Nguyen <quangngmetro@gmail.com> | |
* Version : 0.1 | |
* Copyright : GPL | |
* Description : This is a test application which is used for testing | |
* GPIO output functionality of the raspi-gpio Linux device driver | |
* implemented for Raspberry Pi revision B platform. The test | |
* application first sets all the GPIO pins on the Raspberry Pi to | |
* output, then it sets all the GPIO pins to "high"/"low" logic | |
* level based on the options passed to the program from the command | |
* line | |
* Usage example: | |
* ./output_test 1 // Set all GPIO pins to output, high state | |
* ./output_test 0 // Set all GPIO pins to output, low state | |
*/ | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <string.h> | |
#define NUM_GPIO_PINS 3 | |
#define MAX_GPIO_NUMBER 4 | |
#define BUF_SIZE 4 | |
#define PATH_SIZE 20 | |
int main(int argc, char **argv) | |
{ | |
char path[PATH_SIZE], buf[BUF_SIZE]; | |
int i = 0, fd = 0; | |
snprintf(path, sizeof(path), "/dev/LED_0"); | |
fd = open(path, O_WRONLY); | |
if (fd < 0) { | |
perror("Error opening GPIO pin"); | |
exit(EXIT_FAILURE); | |
} | |
printf("Set GPIO pins to output, logic level :\n"); | |
strncpy(buf, "1", 1); | |
buf[1] = '\0'; | |
if (write(fd, buf, sizeof(buf)) < 0) { | |
perror("write, set pin output"); | |
exit(EXIT_FAILURE); | |
} | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment