嵌入式学习笔记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
设备节点也产生了