.编写LED灯的驱动,创建三个设备文件,每个设备文件和一个LED灯绑定,当操作这个设备文件时只能控制设备文件对应的这盏灯
实验现象
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>
# include "head.h"
void LED_control ( )
{
int a, num, fd;
while ( 1 )
{
printf ( "请输入操作的设备文件:0(LED1) 1(LED2) 2(LED3) 其他字符(重新选择设备文件)>>>" ) ;
scanf ( "%d" , & num) ;
switch ( num)
{
case 0 :
fd = open ( "/dev/myled0" , O_RDWR) ;
break ;
case 1 :
fd = open ( "/dev/myled1" , O_RDWR) ;
break ;
case 2 :
fd = open ( "/dev/myled2" , O_RDWR) ;
break ;
default :
printf ( "输入有误,请重新输入!\n" ) ;
break ;
}
if ( ! ( num == 0 || num == 1 || num == 2 ) )
{
continue ;
}
if ( fd < 0 )
{
printf ( "打开led设备文件失败\n" ) ;
exit ( - 1 ) ;
}
while ( 1 )
{
printf ( "请选择要实现的功能\n" ) ;
printf ( "0(关灯) 1(开灯) 2(重新选择开关灯功能) 其他字符(重新选择设备文件)>>>" ) ;
scanf ( "%d" , & a) ;
if ( a == 1 )
{
ioctl ( fd, LED_ON, & num) ;
}
else if ( a == 0 )
{
ioctl ( fd, LED_OFF, & num) ;
}
else if ( a == 2 )
{
continue ;
}
else
break ;
}
close ( fd) ;
}
}
int main ( int argc, char const * argv[ ] )
{
LED_control ( ) ;
return 0 ;
}
my_chardev.c
# include <linux/init.h>
# include <linux/module.h>
# include <linux/cdev.h>
# include <linux/fs.h>
# include <linux/io.h>
# include <linux/device.h>
# include <linux/slab.h>
# include "head.h"
struct cdev * cdev;
unsigned int major = 500 ;
unsigned int minor = 0 ;
dev_t devno;
struct class * cls;
struct device * dev;
gpio_t * vir_led1;
gpio_t * vir_led2;
gpio_t * vir_led3;
unsigned int * vir_rcc;
int mycdev_open ( struct inode * inode, struct file * file)
{
unsigned int aaa= MINOR ( inode-> i_rdev) ;
file-> private_data= ( void * ) aaa;
printk ( "%s:%s:%d\n" , __FILE__ , __func__ , __LINE__ ) ;
return 0 ;
}
long mycdev_ioctl ( struct file * file, unsigned int cmd, unsigned long arg)
{
unsigned int aaa= ( int ) file-> private_data;
switch ( aaa)
{
case 0 :
switch ( cmd)
{
case LED_ON:
vir_led1-> ODR |= ( 0x1 << 10 ) ;
break ;
case LED_OFF:
vir_led1-> ODR &= ( ~ ( 0X1 << 10 ) ) ;
break ;
}
break ;
case 1 :
switch ( cmd)
{
case LED_ON:
vir_led2-> ODR |= ( 0x1 << 10 ) ;
break ;
case LED_OFF:
vir_led2-> ODR &= ( ~ ( 0X1 << 10 ) ) ;
break ;
}
break ;
case 2 :
switch ( cmd)
{
case LED_ON:
vir_led3-> ODR |= ( 0x1 << 8 ) ;
break ;
case LED_OFF:
vir_led3-> ODR &= ( ~ ( 0X1 << 8 ) ) ;
break ;
}
break ;
}
return 0 ;
}
int all_led_init ( void )
{
vir_led1 = ioremap ( PHY_LED1_ADDR, sizeof ( gpio_t ) ) ;
if ( vir_led1 == NULL )
{
printk ( "ioremap filed:%d\n" , __LINE__ ) ;
return - ENOMEM;
}
vir_led2 = ioremap ( PHY_LED2_ADDR, sizeof ( gpio_t ) ) ;
if ( vir_led2 == NULL )
{
printk ( "ioremap filed:%d\n" , __LINE__ ) ;
return - ENOMEM;
}
vir_led3 = vir_led1;
vir_rcc = ioremap ( PHY_RCC_ADDR, 4 ) ;
if ( vir_rcc == NULL )
{
printk ( "ioremap filed:%d\n" , __LINE__ ) ;
return - ENOMEM;
}
printk ( "物理地址映射成功\n" ) ;
( * vir_rcc) |= ( 3 << 4 ) ;
vir_led1-> MODER &= ( ~ ( 3 << 20 ) ) ;
vir_led1-> MODER |= ( 1 << 20 ) ;
vir_led1-> ODR &= ( ~ ( 1 << 10 ) ) ;
vir_led2-> MODER &= ( ~ ( 3 << 20 ) ) ;
vir_led2-> MODER |= ( 1 << 20 ) ;
vir_led2-> ODR &= ( ~ ( 1 << 10 ) ) ;
vir_led3-> MODER &= ( ~ ( 3 << 16 ) ) ;
vir_led1-> MODER |= ( 1 << 16 ) ;
vir_led1-> ODR &= ( ~ ( 1 << 8 ) ) ;
printk ( "寄存器初始化成功\n" ) ;
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,
. unlocked_ioctl = mycdev_ioctl,
. release = mycdev_close,
} ;
static int __init mycdev_init ( void )
{
int ret, i;
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) , 3 , "myled" ) ;
if ( ret)
{
printk ( "静态指定设备号失败\n" ) ;
goto out2;
}
}
else
{
ret = alloc_chrdev_region ( & devno, minor, 3 , "myled" ) ;
if ( ret)
{
printk ( "动态申请设备号失败\n" ) ;
goto out2;
}
major = MAJOR ( devno) ;
minor = MINOR ( devno) ;
}
printk ( "申请设备号成功\n" ) ;
ret = cdev_add ( cdev, MKDEV ( major, minor) , 3 ) ;
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" ) ;
for ( i = 0 ; i < 3 ; i++ )
{
dev = device_create ( cls, NULL , MKDEV ( major, i) , NULL , "myled%d" , i) ;
if ( IS_ERR ( dev) )
{
printk ( "向上提交节点信息失败\n" ) ;
ret = - PTR_ERR ( dev) ;
goto out5;
}
}
printk ( "向上提交设备节点信息成功\n" ) ;
all_led_init ( ) ;
return 0 ;
out5:
for ( -- i; i >= 0 ; i-- )
{
device_destroy ( cls, MKDEV ( major, i) ) ;
}
class_destroy ( cls) ;
out4:
cdev_del ( cdev) ;
out3:
unregister_chrdev_region ( MKDEV ( major, minor) , 3 ) ;
out2:
kfree ( cdev) ;
OUT1:
return ret;
}
static void __exit mycdev_exit ( void )
{
int i;
for ( i = 0 ; i < 3 ; i++ )
{
device_destroy ( cls, MKDEV ( major, i) ) ;
}
class_destroy ( cls) ;
cdev_del ( cdev) ;
unregister_chrdev_region ( MKDEV ( major, minor) , 3 ) ;
kfree ( cdev) ;
}
module_init ( mycdev_init) ;
module_exit ( mycdev_exit) ;
MODULE_LICENSE ( "GPL" ) ;
head.h
# ifndef __HEAD_H__
# define __HEAD_H__
typedef struct {
volatile unsigned int MODER;
volatile unsigned int OTYPER;
volatile unsigned int OSPEEDR;
volatile unsigned int PUPDR;
volatile unsigned int IDR;
volatile unsigned int ODR;
volatile unsigned int BSRR;
volatile unsigned int LCKR;
volatile unsigned int AFRL;
volatile unsigned int AFRH;
volatile unsigned int BRR;
volatile unsigned int res;
volatile unsigned int SECCFGR;
} gpio_t ;
# define PHY_LED1_ADDR 0X50006000
# define PHY_LED2_ADDR 0X50007000
# define PHY_LED3_ADDR 0X50006000
# define PHY_RCC_ADDR 0X50000A28
# define GPIOB 0X50003000
# define GPIOE 0X50006000
# define GPIOF 0X50007000
# define LED_ON _IOW ( 'l' , 1 , int )
# define LED_OFF _IOW ( 'l' , 0 , int )
# endif