驱动应用层代码
# include <stdio.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <sys/ioctl.h>
# include "head.h"
int main ( int argc, char const * argv[ ] )
{
int a, b;
char buf[ 128 ] = { 0 } ;
int fd_led1 = open ( "/dev/led0" , O_RDWR) ;
if ( fd_led1 < 0 )
{
printf ( "打开LED1设备文件失败\n" ) ;
exit ( - 1 ) ;
}
while ( 1 )
{
printf ( "请选择KEY1灯功能\n" ) ;
printf ( "0(关) 1(开)>" ) ;
scanf ( "%d" , & a) ;
printf ( "请输入要控制的按键\n" ) ;
printf ( "1(KEY1) 2(KEY2) 3(KEY3)>" ) ;
scanf ( "%d" , & b) ;
if ( a == 1 )
{
switch ( b)
{
case 1 :
while ( 1 ) {
read ( fd_led1, buf, sizeof ( buf) ) ;
printf ( "number:%c\n" , buf[ 0 ] ) ;
sleep ( 1 ) ;
}
break ;
case 2 :
break ;
case 3 :
break ;
}
}
else if ( a == 0 )
{
switch ( b)
{
case 1 :
break ;
case 2 :
break ;
case 3 :
break ;
}
}
}
close ( fd_led1) ;
return 0 ;
}
驱动代码
# include <linux/init.h>
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/device.h>
# include <linux/cdev.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/of.h>
# include <linux/of_gpio.h>
# include <linux/gpio.h>
# include <linux/timer.h>
# include <linux/of_irq.h>
# include <linux/interrupt.h>
# include "head.h"
struct cdev * cdev;
unsigned int major= 500 ;
unsigned int minor= 0 ;
dev_t devno;
struct class * cls;
struct device * dev;
int irqno;
struct gpio_desc * gpiono;
struct device_node * dnode;
char number = 0 ;
char kbuf[ 128 ] = { 0 } ;
int mycdev_open ( struct inode * inode, struct file * file)
{
printk ( "%s:%s:%d\n" , __FILE__ , __func__ , __LINE__ ) ;
return 0 ;
}
irqreturn_t myirq_handler ( int irqno, void * dev_id)
{
printk ( "key1 interrupt\n" ) ;
gpiod_set_value ( gpiono, ! gpiod_get_value ( gpiono) ) ;
number = ! number;
return IRQ_HANDLED;
}
ssize_t mycdev_read ( struct file * file, char * ubuf, size_t size, loff_t * lof)
{
int ret;
if ( sizeof ( kbuf) < size)
size= sizeof ( kbuf) ;
kbuf[ 0 ] = number;
printk ( "**************************************%c\n" , number) ;
ret= copy_to_user ( ubuf, kbuf, size) ;
if ( ret)
{
printk ( "copy_to_user filed\n" ) ;
return - EIO;
}
printk ( "%s:%s:%d\n" , __FILE__ , __func__ , __LINE__ ) ;
return 0 ;
}
int mycdev_close ( struct inode * inode, struct file * file)
{
printk ( "%s:%s:%d\n" , __FILE__ , __func__ , __LINE__ ) ;
return 0 ;
}
struct file_operations fops = {
. open = mycdev_open,
. read = mycdev_read,
. release = mycdev_close,
} ;
static int __init mycdev_init ( void )
{
int ret;
int ret1;
cdev= cdev_alloc ( ) ;
if ( cdev== NULL )
{
printk ( "申请字符设备驱动对象空间失败\n" ) ;
ret= - EFAULT;
goto out1;
}
printk ( "字符设备驱动对象申请成功\n" ) ;
cdev_init ( cdev, & fops) ;
if ( major> 0 )
{
ret= register_chrdev_region ( MKDEV ( major, minor) , 1 , "led0" ) ;
if ( ret)
{
printk ( "**********静态指定设备号失败**********\n" ) ;
goto out2;
}
}
else
{
ret= alloc_chrdev_region ( & devno, minor, 1 , "led0" ) ;
if ( ret)
{
printk ( "动态申请设备号失败\n" ) ;
goto out2;
}
major= MAJOR ( devno) ;
minor= MINOR ( devno) ;
}
printk ( "申请设备号成功\n" ) ;
ret= cdev_add ( cdev, MKDEV ( major, minor) , 1 ) ;
if ( ret)
{
printk ( "注册字符设备驱动对象失败\n" ) ;
goto out3;
}
printk ( "注册字符设备驱动对象成功\n" ) ;
cls= class_create ( THIS_MODULE, "led0" ) ;
if ( IS_ERR ( cls) )
{
printk ( "向上提交目录失败\n" ) ;
ret= - PTR_ERR ( cls) ;
goto out4;
}
printk ( "向上提交目录成功\n" ) ;
dev= device_create ( cls, NULL , MKDEV ( major, 0 ) , NULL , "led0" ) ;
if ( IS_ERR ( dev) )
{
printk ( "向上提交节点信息失败\n" ) ;
ret= - PTR_ERR ( dev) ;
goto out5;
}
printk ( "向上提交设备节点信息成功\n" ) ;
dnode= of_find_node_by_name ( NULL , "myleds" ) ;
if ( dnode== NULL )
{
printk ( "解析设备树节点失败\n" ) ;
return - ENOMEM;
}
printk ( "解析设备树节点成功\n" ) ;
gpiono= gpiod_get_from_of_node ( dnode, "led1" , 0 , GPIOD_OUT_LOW, NULL ) ;
if ( IS_ERR ( gpiono) )
{
printk ( "解析设备号失败\n" ) ;
return - PTR_ERR ( gpiono) ;
}
printk ( "申请gpio编号成功\n" ) ;
gpiod_set_value ( gpiono, 1 ) ;
dnode= of_find_node_by_name ( NULL , "mykeys" ) ;
if ( dnode== NULL )
{
printk ( "解析设备树节点失败\n" ) ;
return - ENXIO;
}
printk ( "设备树节点解析成功\n" ) ;
irqno = irq_of_parse_and_map ( dnode, 0 ) ;
if ( ! irqno)
{
printk ( "软中断号获取失败\n" ) ;
return - ENOMEM;
}
printk ( "软中断号获取成功irqno=%d\n" , irqno) ;
ret1 = request_irq ( irqno, myirq_handler, IRQF_TRIGGER_FALLING, "key" , NULL ) ;
if ( ret1)
{
printk ( "注册驱动失败\n" ) ;
return ret1;
}
printk ( "key1中断注册成功\n" ) ;
return 0 ;
out5:
device_destroy ( cls, MKDEV ( major, 0 ) ) ;
class_destroy ( cls) ;
out4:
cdev_del ( cdev) ;
out3:
unregister_chrdev_region ( MKDEV ( major, minor) , 1 ) ;
out2:
kfree ( cdev) ;
out1:
return ret;
}
static void __exit mycdev_exit ( void )
{
gpiod_set_value ( gpiono, 0 ) ;
gpiod_put ( gpiono) ;
free_irq ( irqno, NULL ) ;
device_destroy ( cls, MKDEV ( major, 0 ) ) ;
class_destroy ( cls) ;
cdev_del ( cdev) ;
unregister_chrdev_region ( MKDEV ( major, minor) , 1 ) ;
kfree ( cdev) ;
unregister_chrdev ( major, "led0" ) ;
}
module_init ( mycdev_init) ;
module_exit ( mycdev_exit) ;
MODULE_LICENSE ( "GPL" ) ;