2021-05-12 嵌入式学习笔记1:利用platform实现板子点灯

嵌入式学习笔记1:利用platform实现板子点灯

最近刚淘了台iTOP-4412用来学习linux,写个博文方便自己记录学习过程。

涉及到的知识点

platform总线,misc设备,file_operations结构体。

platform总线

首先可以ls /sys/bus/看一下当前系统都有哪些总线,对于总线这个东西呢,我这么理解的:总线就是遵循某种通信协议的数据传输的手段,比如usb,i2c等,设备之间想要通过某种总线进行信息的交互,必须先得遵守这个通信协议。比如怎么握手,怎么确定数据发送完毕等。对于platform总线要抽象一下,理解成对设备和驱动的一种管理手段,主要是为了降低设备和驱动之间的耦合。将设备和驱动都注册到该总线上,总线会将设备和驱动进行配对。platform有两个链表,驱动链表和设备链表,当你注册驱动到链表上,会根据注册的名字去设备链表上查相应的设备,反之 ,当注册了一个新的设备,会去查相应的驱动。

相关函数在内核代码的include/linux/platform_device.h中。

struct platform_driver {
120         int (*probe)(struct platform_device *);//配对成功则运行该函数
121         int (*remove)(struct platform_device *);
122         void (*shutdown)(struct platform_device *);
123         int (*suspend)(struct platform_device *, pm_message_t state);
124         int (*resume)(struct platform_device *);
125         struct device_driver driver;
126         const struct platform_device_id *id_table;
127 };
 struct platform_device {
 20         const char      * name;//配对用的名字
 21         int             id;
 22         struct device   dev;
 23         u32             num_resources;
 24         struct resource * resource;
 25 
 26         const struct platform_device_id *id_entry;
 27 
 28         /* MFD cell pointer */
 29         struct mfd_cell *mfd_cell;
 30 
 31         /* arch specific additions */
 32         struct pdev_archdata    archdata;
 33 };
extern int platform_driver_register(struct platform_driver *);
extern void platform_driver_unregister(struct platform_driver *);
注册和卸载驱动

extern int platform_device_register(struct platform_device *);
extern void platform_device_unregister(struct platform_device *);
注册和卸载设备

misc设备

 misc杂项设备,主设备号为10。

struct miscdevice  {
	int minor; //次设备号
	const char *name;  //驱动名字
	const struct file_operations *fops;
	struct list_head list; 
	struct device *parent; //空的话是注册到/sys/class下
	struct device *this_device;。
	const char *nodename;
	umode_t mode;
};

file_operations

这个 在include/linux/fs.h中,这次试验就用了以下几个函数

struct file_operations {
        struct module *owner;
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        int (*open) (struct inode *, struct file *);
        int (*release) (struct inode *, struct file *);
        ...
};

全部代码

#include<linux/module.h>
#include<linux/fs.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include<linux/platform_device.h>
#include<linux/miscdevice.h>
#include<linux/gpio.h>//gpio request set等
#include<plat/gpio-cfg.h>//s3c_gpio_cfgpin函数,S3C_GPIO_OUTPUT 宏定义
#include<mach/gpio.h>
#include<mach/gpio-exynos4.h>//EXYNOS4_GPK1定义
#include<linux/miscdevice.h>
#define DRIVER_NAME "led_test"
#define DEVICE_MISC_NAME "led_misc_test"
#define DEVICE_PLAT_NAME "led_test"

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("CASEY");


static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	printk("cmd is %d, arg is %d \n",cmd,arg);
	if(cmd==1){
		gpio_set_value(EXYNOS4_GPK1(1),1);
		gpio_set_value(EXYNOS4_GPL2(0),0);
	}
	else{
		gpio_set_value(EXYNOS4_GPK1(1),0);
		gpio_set_value(EXYNOS4_GPL2(0),1);
	}
	return 0;
}

static int led_open(struct inode inode, struct file *file)
{
	printk("led open\n");
	return 0;
}

static int led_release(struct inode *inode, struct file *file)
{
	printk("led release\n");
	return 0;
}

static struct file_operations led_fops={
	.owner = THIS_MODULE,
	.open = led_open,
	.release = led_release,//close 
	.unlocked_ioctl = led_ioctl, 	
};
static struct miscdevice led_misc_dev={
	.minor = MISC_DYNAMIC_MINOR, //10
	.name = DEVICE_MISC_NAME,//要与driver中的一致才可配对
	.fops = &led_fops,
};
static void plat_led_release(struct device *dev){
	printk(KERN_EMERG "platfrom_device_release\n");
}
static struct platform_device led_plat_dev ={
	.name = DEVICE_PLAT_NAME,
	.id = -1,
	.dev = {
		.release = plat_led_release,
			        }
};

static int led_probe(struct platform_device *pdv)
{
	int ret ;
	printk(KERN_EMERG "led probe \n");

	ret = gpio_request(EXYNOS4_GPL2(0),"led_test1");//被占用申请失败,但是不影响使用
	if(ret<0){
		printk(KERN_EMERG "gpio_register  GPL2 failed  ret =%d\n",ret);
	}
	ret = s3c_gpio_cfgpin(EXYNOS4_GPL2(0),S3C_GPIO_OUTPUT);
	printk(KERN_EMERG "cfg pin ret=%d \n",ret);
	gpio_set_value(EXYNOS4_GPL2(0),0);
	ret = gpio_request(EXYNOS4_GPK1(1),"led_test2");
	if(ret<0){
		printk(KERN_EMERG "gpio_register GPK1 failed \n");
	}
	s3c_gpio_cfgpin(EXYNOS4_GPK1(1),S3C_GPIO_OUTPUT);
	gpio_set_value(EXYNOS4_GPK1(1),0);
	misc_register(&led_misc_dev);//生成/dev/led_misc_dev
	return 0;
}
static int led_remove(struct platform_device *pdv)
{
	misc_deregister(&led_misc_dev);
	printk(KERN_EMERG "led remove \n");
	return 0;
}

static void led_shutdown(struct platform_device *pdv)
{
	printk(KERN_EMERG "led shutdown\n");
}

static int led_suspend(struct platform_device *pdv)
{
	printk(KERN_EMERG "led suspend \n");
	return 0;
}

static int led_resume(struct platform_device *pdv)
{
	printk(KERN_EMERG "led resume \n");
	return 0;
}

struct platform_driver led_driver={
	.probe = led_probe,
	.remove = led_remove,
	.shutdown = led_shutdown,
	.suspend = led_suspend,
	.resume = led_resume,
	.driver ={
		.name = DRIVER_NAME,//要与device中的一致
		.owner = THIS_MODULE,
	}

};

static int led_init(void)
{
	int ret;
	printk(KERN_EMERG "led diver Init\n");
	ret = platform_driver_register(&led_driver);
	printk(KERN_EMERG "led diver ret = %d\n",ret);
	ret = platform_device_register(&led_plat_dev);//现在基本都用设备树,注册点在/sys/devices/platform/
	printk(KERN_EMERG "led device ret = %d\n",ret);
	return 0;
}
static void led_exit(void)
{
	printk(KERN_EMERG "led driver exit\n");
	platform_driver_unregister(&led_driver);
	platform_device_unregister(&led_plat_dev);
}
module_init(led_init);
module_exit(led_exit);

其中我是动态注册的platform device ,一开始没有注册devices,probe函数没有执行。编译运行,加载模块。实验结果如下:

此设备号是46

设备节点也产生了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值