点亮IMX6ULL开发板LED2,通过输入 on/off控制LED亮灭以及查看灯状态
cat /sys/kernel/debug/gpio
#include "asm-generic/errno-base.h"
#include "asm-generic/gpio.h"
#include "asm/uaccess.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct gpio_desc{
int gpio;
int irq;
char *name;
int key;
struct timer_list key_timer;
} ;
static struct gpio_desc gpios[2] = {
{131, 0, "led0", },
//{132, 0, "led1", },
};
/* 主设备号 */
static int major = 0;
static struct class *gpio_class;
/* 实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
char tmp_buf[2];
int err;
int count = sizeof(gpios)/sizeof(gpios[0]);
if (size != 2)
return -EINVAL;
//buf用户空间buf
//从用户空间拷贝数数据
err = copy_from_user(tmp_buf, buf, 1);
if (tmp_buf[0] >= count)
return -EINVAL;
tmp_buf[1] = gpio_get_value(gpios[tmp_buf[0]].gpio);
//拷贝数据到用户空间
err = copy_to_user(buf, tmp_buf, 2);
return 2;
}
static ssize_t gpio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
unsigned char ker_buf[2];
int err;
if (size != 2)
return -EINVAL;
err = copy_from_user(ker_buf, buf, size);
if (ker_buf[0] >= sizeof(gpios)/sizeof(gpios[0]))
return -EINVAL;
gpio_set_value(gpios[ker_buf[0]].gpio, ker_buf[1]);
return 2;
}
/* 定义自己的file_operations结构体 */
static struct file_operations gpio_key_drv = {
.owner = THIS_MODULE,
.read = gpio_drv_read,
.write = gpio_drv_write,
};
/* 在入口函数 */
static int __init gpio_drv_init(void)
{
int err;
int i;
int count = sizeof(gpios)/sizeof(gpios[0]);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
for (i = 0; i < count; i++)
{
/* set pin as output */
//申请GPIO
err = gpio_request(gpios[i].gpio, gpios[i].name);
if (err < 0) {
printk("can not request gpio %s %d\n", gpios[i].name, gpios[i].gpio);
return -ENODEV;
}
//输出模式
gpio_direction_output(gpios[i].gpio, 1);
}
/* 注册file_operations */
major = register_chrdev(0, "100ask_led", &gpio_key_drv); /* /dev/gpio_desc */
//创建类
gpio_class = class_create(THIS_MODULE, "100ask_led_class");
if (IS_ERR(gpio_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "100ask_led_class");
return PTR_ERR(gpio_class);
}
//创建设备名
device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "100ask_led"); /* /dev/100ask_gpio */
return err;
}
/* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
*/
static void __exit gpio_drv_exit(void)
{
int i;
int count = sizeof(gpios)/sizeof(gpios[0]);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
device_destroy(gpio_class, MKDEV(major, 0));
class_destroy(gpio_class);
unregister_chrdev(major, "100ask_led");
for (i = 0; i < count; i++)
{
gpio_free(gpios[i].gpio);
}
}
/* 7. 其他完善:提供设备信息,自动创建设备节点 */
module_init(gpio_drv_init);
module_exit(gpio_drv_exit);
MODULE_LICENSE("GPL");
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int fd;
//int led_on(int which);
//int led_off(int which);
//int led_status(int which);
/*
* ./led_test <0|1|2|..> on
* ./led_test <0|1|2|..> off
* ./led_test <0|1|2|..>
*/
int main(int argc, char **argv)
{
int ret;
char buf[2];
int i;
/* 1. 判断参数 */
if (argc < 2)
{
printf("Usage: %s <0|1|2|...> [on | off]\n", argv[0]);
return -1;
}
/* 2. 打开文件 */
fd = open("/dev/100ask_led", O_RDWR);
if (fd == -1)
{
printf("can not open file /dev/100ask_led\n");
return -1;
}
//argc参数个数
if (argc == 3)
{
/* write */
//将argv[1]转为整形
buf[0] = strtol(argv[1], NULL, 0);
if (strcmp(argv[2], "on") == 0)
buf[1] = 0;
else
buf[1] = 1;
ret = write(fd, buf, 2);
}
else
{
buf[0] = strtol(argv[1], NULL, 0);
ret = read(fd, buf, 2);
if (ret == 2)
{
printf("led %d status is %s\n", buf[0], buf[1] == 0 ? "on" : "off");
}
}
close(fd);
return 0;
}
KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88 # 板子所用内核源码的目录
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o led_test led_test.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order led_test
# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o
obj-m += led_drv.o
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
insmod led_drv.ko
查看设备节点
ls /dev/100ask_led
0:第0个灯,灯序号 on点亮 off熄灭
./led_test 0 on
0:第0个灯,灯序号 on点亮 off熄灭
./led_test 0 off
0:第0个灯,灯序号 on点亮 off熄灭
(on/ off不输入则检测当前灯状态)
./led_test 0