2.作业 platform驱动实现
platform.c
# 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/gpio.h>
# include <linux/of_gpio.h>
# include <linux/uaccess.h>
# include <linux/of_irq.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/mod_devicetable.h>
struct cdev * cdev;
unsigned int major = 0 ;
unsigned int minor = 0 ;
dev_t devno;
struct class * cls;
struct device * dev;
char number = '0' ;
unsigned int irqno;
struct gpio_desc * gpiono;
wait_queue_head_t wq_head;
unsigned int condition = 0 ;
irqreturn_t myirq_handler ( int irqno, void * dev_id)
{
if ( number == '0' )
{
number = '1' ;
gpiod_set_value ( gpiono, 1 ) ;
}
else
{
number = '0' ;
gpiod_set_value ( gpiono, 0 ) ;
}
condition = 1 ;
wake_up_interruptible ( & wq_head) ;
return IRQ_HANDLED;
}
int mycdev_open ( struct inode * inode, struct file * file)
{
return 0 ;
}
ssize_t mycdev_read ( struct file * file, char * ubuf, size_t size, loff_t * lof)
{
int ret;
wait_event_interruptible ( wq_head, condition) ;
printk ( "size=%d\n" , size) ;
ret = copy_to_user ( ubuf, & number, size) ;
if ( ret)
{
printk ( "copy_to_user filed\n" ) ;
return - EIO;
}
printk ( "num%c\n" , number) ;
condition = 0 ;
return 0 ;
}
ssize_t mycdev_write ( struct file * file, const char * ubuf, size_t size, loff_t * lof)
{
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,
. write = mycdev_write,
. release = mycdev_close,
} ;
int pdrv_probe ( struct platform_device * pdev)
{
int ret;
init_waitqueue_head ( & wq_head) ;
irqno = platform_get_irq ( pdev, 0 ) ;
if ( irqno < 0 )
{
printk ( "获取中断资源失败\n" ) ;
return irqno;
}
printk ( "获取中断资源成功%d\n" , irqno) ;
ret = request_irq ( irqno, myirq_handler, IRQF_TRIGGER_FALLING, "key1" , NULL ) ;
if ( ret)
{
printk ( "注册驱动失败\n" ) ;
return ret;
}
printk ( "key1中断注册成功\n" ) ;
gpiono = gpiod_get_from_of_node ( pdev-> dev. of_node, "led1" , 0 , GPIOD_OUT_LOW, NULL ) ;
if ( IS_ERR ( gpiono) )
{
printk ( "gpio编号解析失败" ) ;
return - PTR_ERR ( gpiono) ;
}
gpiod_set_value ( gpiono, 0 ) ;
cdev = cdev_alloc ( ) ;
if ( NULL == cdev)
{
printk ( "字符设备驱动对象空间失败\n" ) ;
ret = - EFAULT;
goto out1;
}
printk ( "字符设备驱动对象空间申请成功" ) ;
cdev_init ( cdev, & fops) ;
if ( major > 0 )
{
ret = register_chrdev_region ( MKDEV ( major, minor) , 1 , "myled" ) ;
if ( ret)
{
printk ( "静态指定设备号失败\n" ) ;
goto out2;
}
}
else
{
ret = alloc_chrdev_region ( & devno, minor, 1 , "myled" ) ;
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, "myled" ) ;
if ( IS_ERR ( cls) )
{
printk ( "向上提交目录失败\n" ) ;
ret = - PTR_ERR ( cls) ;
goto out4;
}
printk ( "向上提交目录成功\n" ) ;
dev = device_create ( cls, NULL , MKDEV ( major, 0 ) , NULL , "myled" ) ;
if ( IS_ERR ( dev) )
{
printk ( "向上提交设备节点信息失败\n" ) ;
ret = - PTR_ERR ( dev) ;
goto out5;
}
printk ( "线上提交设备节点信息成功\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;
}
int pdrv_remove ( struct platform_device * pdev)
{
gpiod_set_value ( gpiono, 0 ) ;
device_destroy ( cls, MKDEV ( major, 0 ) ) ;
class_destroy ( cls) ;
cdev_del ( cdev) ;
unregister_chrdev_region ( MKDEV ( major, minor) , 1 ) ;
kfree ( cdev) ;
gpiod_put ( gpiono) ;
free_irq ( irqno, NULL ) ;
return 0 ;
}
struct of_device_id oftable[ ] = {
{ . compatible= "hqyj,myplatform" , } ,
{ . compatible= "hqyj,myplatform1" , } ,
{ } ,
} ;
struct platform_driver pdrv= {
. probe = pdrv_probe,
. remove = pdrv_remove,
. driver = {
. name = "aaaaa" ,
. of_match_table = oftable,
} ,
} ;
module_platform_driver ( pdrv) ;
MODULE_LICENSE ( "GPL" ) ;
test.c
# include <stdlib.h>
# include <stdio.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <sys/ioctl.h>
int main ( int argc, char const * argv[ ] )
{
int fd;
char number;
fd = open ( "/dev/myled" , O_RDWR) ;
if ( fd < 0 )
{
printf ( "打开文件失败\n" ) ;
exit ( - 1 ) ;
}
while ( 1 )
{
read ( fd, & number, sizeof ( number) ) ;
printf ( "number = %c\n" , number) ;
}
close ( fd) ;
return 0 ;
}