head.h

#ifndef __HEAD_H__

#define __HEAD_H__

typedef struct{

unsigned int MODER;

unsigned int OTYPER;

unsigned int OSPEEDR;

unsigned int PUPDR;

unsigned int IDR;

unsigned int ODR;

}gpio_t;

#define PHY_LED1_ADDR 0X50006000

#define PHY_LED2_ADDR 0X50007000

#define PHY_LED3_ADDR 0X50006000

#define PHY_RCC_ADDR 0X50000A28

#define LED_ON _IOW('l',1,int)

#define LED_OFF _IOW('l',0,int)

#endif

驱动文件

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include"head.h"

unsigned int major=0;//主设备号

unsigned int minor=0;//次设备号

dev_t devno;

struct cdev *cdev;

gpio_t *vir_led1;

gpio_t *vir_led2;

gpio_t *vir_led3;

unsigned int *vir_rcc;

char kbuf[128]={0};

struct class *cls;

struct device *dev;

int mycdev_open(struct inode *inode, struct file *file)

{

printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);

return 0;

}

ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)

{

printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);

unsigned long ret;

//向用户空间读取拷贝

if(size>sizeof(kbuf))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小

size=sizeof(kbuf);

ret=copy_to_user(ubuf,kbuf,size);

if(ret)//拷贝失败

{

printk("copy_to_user filed\n");

return ret;

}

return 0;

}

ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)

{

unsigned long ret;

// 从用户空间读取数据

if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小

size = sizeof(kbuf);

ret = copy_from_user(kbuf, ubuf, size);

if (ret) // 拷贝失败

{

printk("copy_to_user filed\n");

return ret;

}

return 0;

}

long mycdev_ioctl (struct file *file, unsigned int cmd, unsigned long arg)

{

int ar;

int ret;

ret=copy_from_user(&ar,(void*)arg,4);

if(ret)//拷贝失败

{

printk("copy_to_user filed\n");

return ret;

}

switch(cmd)

{

case LED_ON:

switch(ar)

{

case 0:

vir_led1->ODR |= 1<<10;

break;

case 1:

vir_led2->ODR |= 1<<10;

break;

case 2:

vir_led3->ODR |= 1<<8;

break;

}

break;

case LED_OFF:

switch(ar)

{

case 0:

vir_led1->ODR &= (~(1<<10));

break;

case 1:

vir_led2->ODR &= (~(1<<10));

break;

case 2:

vir_led3->ODR &= (~(1<<8));

break;

}

break;

}

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={

.unlocked_ioctl=mycdev_ioctl,

.open=mycdev_open,

.read=mycdev_read,

.write=mycdev_write,

.release=mycdev_close,

};

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");

//寄存器的初始化

//rcc

(*vir_rcc) |= (3<<4);

//led1

vir_led1->MODER &= (~(3<<20));

vir_led1->MODER |= (1<<20);

vir_led1->ODR &= (~(1<<10));

//led2

vir_led2->MODER &= (~(3<<20));

vir_led2->MODER |= (1<<20);

vir_led2->ODR &= (~(1<<10));

//led3

vir_led3->MODER &= (~(3<<16));

vir_led1->MODER |= (1<<16);

vir_led1->ODR &= (~(1<<8));

printk("寄存器初始化成功\n");

return 0;

}

static int __init mycdev_init(void)

{

int ret;

//1.创建驱动对象

cdev=cdev_alloc();

if(cdev==NULL)

{

return -ENOMEM;

}

printk("驱动对象创建成功\n");

//2.驱动对象初始化

cdev_init(cdev, &fops);

//3.申请设备号

ret=alloc_chrdev_region(&devno, 0 ,3,"myled");

if(ret)

{

printk("设备号申请失败\n");

goto out;

}

major=MAJOR(devno);

minor=MINOR(devno);

printk("设备号申请成功\n");

//4.驱动注册

ret=cdev_add(cdev,devno,3);

if(ret)

{

printk("驱动注册失败\n");

goto out1;

}

printk("驱动注册成功\n");

//5.向上提交目录

cls=class_create(THIS_MODULE,"led");

if(IS_ERR(cls))

{

printk("向上提交目录失败\n");

ret=-PTR_ERR(cls);

goto out2;

}

printk("向上提交目录成功\n");

//6.向上提交节点

int i;

//向上提交三次设备节点信息

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 out3;

}

}

printk("向上提交设备节点成功\n");

//寄存器映射以及初始化

all_led_init();

return 0;

out3:

for(--i;i>=0;i--)

{

device_destroy(cls,MKDEV(major,i));

}

class_destroy(cls);

out2:

cdev_del(cdev);

out1:

unregister_chrdev_region(devno,3);

out:

kfree(cdev);

return ret;

}

static void __exit mycdev_exit(void)

{

//取消地址映射

iounmap(vir_led1);

iounmap(vir_led2);

iounmap(vir_rcc);

//销毁节点

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");

应用文件

#include

#include

#include

#include

#include

#include

#include

#include

#include "head.h"

int main(int argc, char const *argv[])

{

int a,b;

char buf[128]={0};

int fd=open("/dev/myled0",O_RDWR);

if(fd<0)

{

printf("打开设备文件失败\n");

exit(-1);

}

while(1)

{

//从终端读取

printf("请输入功能选择\n");

printf("0(关灯) 1(开灯)\n");

printf("请输入>");

scanf("%d",&a);

printf("请输入灯选择\n");

printf("0(led0) 1(led1) 2(led2)\n");

printf("请输入>");

scanf("%d",&b);

switch(a)

{

case 1:

ioctl(fd,LED_ON,&b);

break;

case 0:

ioctl(fd,LED_OFF,&b);

break;

}

}

close(fd);

return 0;

}

现象实现

推荐链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。