驱动day4

chrdev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include"myled.h"
#define CNAME  "myled"
;
unsigned int major=500;//定义变量接收主设备号
int minor=0;
char kbuf[128]={};//定义数组用于存放和用户之间拷贝的数据
struct cdev *cdev;
struct class *cls;//句柄
struct device *dev;
unsigned int *vir_rcc;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;

const int count=3;

//对应的是open()
int mycdev_open(struct inode *inode, struct file *file)
{
      printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
      return 0;
}

//read()
ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
	//size参数是用户期待读到的字节长度
	int ret;
	if(size>sizeof(kbuf))
		size=sizeof(kbuf);
	ret=copy_to_user(ubuf,kbuf,size);
	if(ret)
	{
		printk("数据从内核向用户拷贝失败\n");
		return -EIO;
	}
	return size;
}

//write()
ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
    int ret;
    if(size>sizeof(kbuf))
    size=sizeof(kbuf);
    ret=copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("数据从内核向用户拷贝失败\n");
        return -EIO;
    }
    
       return size;
}

//close()
int mycdev_close(struct inode *inode, struct file *file)
{
      printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
       return 0;
}

long ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
	int ret,which;
	switch(cmd)
	{
		case LedON:
			ret=copy_from_user(&which,(void *)arg,sizeof(int));
			if(ret)
			{
				printk("用户向内核拷贝数据失败\n");
				return -EIO;
			}
			switch(which)
			{
				case LED1:
					vir_led1->ODR |=(1<<10);
					break;
				case LED2:
					vir_led2->ODR |=(1<<10);
					break;
				case LED3:
					vir_led3->ODR |=(1<<8);
					break;
			}
			break;
		case LedOFF:
			ret=copy_from_user(&which,(void *)arg,sizeof(int));
			if(ret)
			{
				printk("用户向内核拷贝数据失败\n");
				return -EIO;
			}
			switch(which)
			{
			case LED1:
				vir_led1->ODR &=~(1<<10);
				break;
			case LED2:
				vir_led2->ODR &=~(1<<10);
				break;
			case LED3:
				vir_led3->ODR &=~(1<<8);
				break;
			}
			break;
		default:
			printk("功能码错误\n");
			break;
	}
	return 0;
}

//操作方法结构体的初始化
struct file_operations fops=
{
    .open=mycdev_open,
    .read=mycdev_read,
    .write=mycdev_write,
	.unlocked_ioctl=ioctl,
    .release=mycdev_close,
};

int all_led_init(void)
{
    //进行物理地址的映射
    vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));
    if(vir_led1==NULL)
    {
        printk("vir_led1 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_led1 映射成功\n");
   vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
    if(vir_led2==NULL)
    {
        printk("vir_led2 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_led2 映射成功\n");
    vir_led3=ioremap(PHY_LED3_ADDR,sizeof(gpio_t));
    if(vir_led3==NULL)
    {
        printk("vir_led3 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_led3 映射成功\n");
    vir_rcc=ioremap(PHY_RCC_ADDR,4);
    if(vir_rcc==NULL)
    {
        printk("vir_rcc 映射失败\n");
        return -ENOMEM;
    }
    printk("vir_rcc 映射成功\n");
    //寄存器的初始化
    //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_led3->MODER |= (1<<16);
    vir_led3->ODR &= ~(1<<8);

    (*vir_rcc) |= (3<<4);
    return 0;
}


static int __init mycdev_init(void)
{
	int ret,i;
	//1.分配设备驱动对象
	//dev_t devno;
	cdev=cdev_alloc();
	if(cdev==NULL)
	{
		printk("分配设备驱动对象失败\n");

		ret= -ENOMEM;
		goto ERR1;
	}
	printk("对象分配成功\n");
	//2.初始化对象
	cdev_init(cdev,&fops);
	//3.设备号的申请
	ret=register_chrdev_region(MKDEV(major,minor),count,"my_led");
	if(ret)
	{
		printk("设备号申请失败\n");
		goto ERR2;
	}
	printk("设备号申请成功\n");
	//ret=alloc_chrdev_region(&devno,minor,1,"myled");
	//if
	//major=MAJOR(devno);

	//4.注册字符设备驱动
	ret=cdev_add(cdev,MKDEV(major,minor),count);
	if(ret)
	{
		printk("注册字符设备驱动失败\n");
		goto ERR3;
	}
	printk("注册字符设备驱动成功\n");
	//5.自动创建设备节点
	cls=class_create(THIS_MODULE,"led");
	if(IS_ERR(cls))
	{
		printk("向上提交目录失败\n");
		ret=PTR_ERR(cls);
		goto ERR4;
	}
	printk("向上提交目录成功\n");

	//创建设备节点
	for(i=0;i<3;i++)
	{
		dev=device_create(cls,NULL,MKDEV(major,i),NULL,"my_led%d",i);
		if(IS_ERR(dev))
		{
			printk("创建节点失败\n");
			ret=PTR_ERR(dev);
			goto ERR5;
		}
		printk("创建节点成功\n");
	}
	all_led_init();
	return 0;
ERR5:
	for(--i;i>=0;i--)
	{
		device_destroy(cls,MKDEV(major,i));	
	}
	class_destroy(cls);
ERR4:
	cdev_del(cdev);
ERR3:
	unregister_chrdev_region(MKDEV(major,minor),count);
ERR2:
	kfree(cdev);
ERR1:
	return ret;
}

static void __exit mycdev_exit(void)
{
	//1.销毁设备节点
	int i;
	for(i=0;i<count;i++)
	{
		device_destroy(cls,MKDEV(major,i));
	}
	//销毁目录
	class_destroy(cls);
	iounmap(vir_led1);
	iounmap(vir_rcc);
	//2.字符设备驱动注销
	cdev_del(cdev);
	//3.释放设备号
	unregister_chrdev_region(MKDEV(major,minor),count);
	//4.释放动态申请空间
	kfree(cdev);
}


module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值