嵌入式学习笔记——platform设备
来源:互联网 发布:淘宝卖家上传图片失败 编辑:程序博客网 时间:2024/06/06 15:43
platform机制将本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform_device提供的标准接口进行申请并使用。
开发环境:ubuntu 12.04
开发板:龙芯1B开发板
交叉编译工具:gcc-4.3-ls232-softfloat
内核版本:3.0.0
platform的设备可以有两种形式,一种是将设备编译在内核中,在内核初始化的时候,将资源注册到内核里;一种是以加载的方式,将设备资源注册在内核中。
如果是编译在内核中的,就要修改内核中,对应cpu型号的platform.c,以我现在用的龙芯1b开发板为例,打开linux3.0.0/arch/mips/loongson/ls1x/ls1x-board/platform.c,里面的代码大致上分为两大部分,一部分用于定义各个设备结构和资源,以龙芯1b里的pwm设备为例
//分别定义pwm寄存器的首地址,此处地址是物理地址#define LS1B_PWM0_BASE 0x1fe5c000#define LS1B_PWM1_BASE 0x1fe5c010#define LS1B_PWM2_BASE 0x1fe5c020#define LS1B_PWM3_BASE 0x1fe5c030//设备的变量static struct platform_device ls1b_pwm_device = { //定义一个ls1b的pwm的设备 .name = "ls1b-pwm", //设备名称 .id = -1, .num_resources = ARRAY_SIZE(ls1b_pwm0_resource), //资源数量 .resource = ls1b_pwm0_resource, //资源名称};//设备资源static struct resource ls1b_pwm0_resource[] = { //定义一个ls1b的pwm的资源 [0]={ //因为龙芯1b系列内置四路pwm输出,所以要将每路的资源分别定义 .start = LS1B_PWM0_BASE, //这是pwm0第一个寄存器的物理地址,在这里用的是物理地址而不是 //虚拟地址是因为platform机制是CPU直接寻址设备的寄存器空间 .end = (LS1B_PWM0_BASE + 0x0f), //这是pwm0最后一个寄存器的物理地址 .flags = IORESOURCE_MEM, //标识资源的类型,在这是可直接寻址空间 }, [1]={ .start = LS1B_PWM1_BASE, .end = (LS1B_PWM1_BASE + 0x0f), .flags = IORESOURCE_MEM, }, [2]={ .start = LS1B_PWM2_BASE, .end = (LS1B_PWM2_BASE + 0x0f), .flags = IORESOURCE_MEM, }, [3]={ .start = LS1B_PWM3_BASE, .end = (LS1B_PWM3_BASE + 0x0f), .flags = IORESOURCE_MEM, }, };
第二部分是将定义好的设备添加到platform设备数组里,然后注册到内核中,由内核统一管理。
static struct platform_device *ls1b_platform_devices[] __initdata = { //将定义好的设备结构添加到该数组中 &ls1b_pwm0_device, &ls1x_fb0_device, &ls1b_nand_device, &ls1b_ohci_device, &ls1b_ehci_device, &ls1b_gmac0_mac, &ls1b_gmac0_phy,//以下省略其他的设备 };int __init ls1b_platform_init(void) { //在此可以添加一些简单的初始化 return platform_add_devices(ls1b_platform_devices, ARRAY_SIZE(ls1b_platform_devices)); //将platform设备列表添加到内核中} arch_initcall(ls1b_platform_init); //在include/linux/init.h中,是这样定义的“#define arch_initcall(fn) module_init(fn)”,所以应该是用来声明模块初始化入口
到此为止,设备的申请已经完成了。下面在看一下driver/char/ls1b-pwm.c,这是pwm的驱动程序。以下是部分代码:
static struct platform_driver ls1f_pwm_driver = { //定义一个platform_driver结构的变量 .probe = ls1f_pwm_probe, //定义.probe所指向的函数ls1b_pwm_probe .driver = { .name = "ls1b-pwm", //定义该设备的名称,这名称将会与之前内核初始化所申请的platform设备一一对比,当对比到有一样的时候,将自动调用probe函数 }, }; static int ls1f_pwm_open(struct inode *inode, struct file *file) //file_operations结构中的open函数,用于应用程序调用该驱动时,打开驱动。 { long val = readl(SB2F_GPIO_MUX_CTRL1); val &= 0xfffffffc; writel(val, SB2F_GPIO_MUX_CTRL1); val = readl(REG_GPIO_CFG0); //配置GPIO复用为使用PWM工作的模式 val &= 0xfffffff0; writel(val, REG_GPIO_CFG0); return 0; } static int ls1f_pwm_close(struct inode *inode, struct file *file) //用于关闭驱动调用 { writeb(0x0, pwm_base + REG_PWM_CTRL); return 0; } static ssize_t ls1f_pwm_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) //对设备进行读操作{ unsigned int pwm_val; pwm_val = readl(pwm_base); if (copy_to_user(buf, &pwm_val, sizeof(unsigned int))) return -EFAULT; return 4; } static ssize_t ls1f_pwm_write(struct file *file, const char __user *buf, size_t count, loff_t *ptr)//用于对设备进行写操作 { unsigned int hrc_val, lrc_val; unsigned int data[2] = {0x0}; if (copy_from_user(data, buf, sizeof(data))) { printk("Write error!\n"); return -EIO; } hrc_val = data[1] - 1; lrc_val = data[0] + data[1] -1; //设置占空比 writel(hrc_val, pwm_base + REG_PWM_HRC); writel(lrc_val, pwm_base + REG_PWM_LRC); return 0; } static long ls1f_pwm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) //对设备的I/O通道进行管理{ printk("into %s\n", __FUNCTION__); printk("cmd: %d\n", cmd); printk("arg: %ld\n", arg); if (arg > 3) return -1; switch (cmd) { case CMD_PWM_GET: ls1f_pwm_getResourse(pwm_dev, arg); break; case CMD_PWM_START: case CMD_PWM_STOP: return pwm_start_stop(cmd, arg); default: break; } return 0; } static const struct file_operations ls1f_pwm_ops = { //file_operations结构是一个虚拟文件系统,通过该结构对设备进行操作,就是说用于驱动程序与设备的交互 .owner = THIS_MODULE, //将结构指向该模块 .open = ls1f_pwm_open, //将结构中open函数与我们编写的open函数关联,以后应用程序调用open的时候,就会调用到我们写的open函数 .release = ls1f_pwm_close, //同上 .read = ls1f_pwm_read, .write = ls1f_pwm_write, .unlocked_ioctl = ls1f_pwm_ioctl, }; static struct miscdevice ls1f_pwm_miscdev = { //定义一个杂项字符设备结构类型的变量 MISC_DYNAMIC_MINOR, //动态获取次设备号 "ls1f-pwm", //设备名称 &ls1f_pwm_ops, //关联file_opertiaons结构 }; static int ls1f_pwm_getResourse(struct platform_device *pdev, unsigned int index) //该函数是用来获取在内核中申请到的设备资源{ res = platform_get_resource(pdev, IORESOURCE_MEM, index); if (res == NULL) { printk("Fail to get ls1f_pwm_resource!\n"); return -ENOENT; } printk("Resource start=0x%x, end = 0x%x\n", res->start, res->end); if (res1 != NULL) { release_mem_region(res->start, 0x0f); } res1 = request_mem_region(res->start, 0x0f, "ls1f-pwm"); if (res1 == NULL) { printk("Fail to request ls1f_pwm region!\n"); return -ENOENT; } pwm_base = ioremap(res->start, res->end - res->start + 1); if (pwm_base == NULL) { printk("Fail to ioremap ls1f_pwm resource!\n"); return -EINVAL; } return 0; } static int __devinit ls1f_pwm_probe(struct platform_device *pdev) //当初始化设备时,我们申请设备名称已经在内核管理的platform设备中存在,就会自动调用该函数 { pwm_dev = pdev; return ls1f_pwm_getResourse(pdev, 1); //获取内核中已申请的设备资源 } static int __init ls1f_pwm_init(void) { //模块初始化函数 if (misc_register(&ls1f_pwm_miscdev)) //注册杂项字符设备,会自动创建设备节点,即设备文件 { printk(KERN_WARNING "pwm: Couldn't register device 10, %d.\n", 255); return -EBUSY; } return platform_driver_register(&ls1f_pwm_driver); //注册platform设备,如果这时发现设备已存在,就会自动调用probe函数} static void __exit ls1f_pwm_exit(void) //模块卸载函数{ misc_deregister(&ls1f_pwm_miscdev); //从杂项字符设备中注销该设备 release_mem_region(res->start, 0x20); //用于释放不需要的I/O内存区 platform_driver_unregister(&ls1f_pwm_driver); //从platform中注销驱动} module_init(ls1f_pwm_init); module_exit(ls1f_pwm_exit); MODULE_AUTHOR("<xuhongmeng xuhongmeng-gz@loongson.cn>"); MODULE_DESCRIPTION("loongson 1B PWM driver"); MODULE_LICENSE("GPL");
0 0
- 嵌入式学习笔记——platform设备
- 嵌入式Linux驱动笔记(五)------学习platform设备驱动
- 嵌入式学习笔记——字符设备驱动编写
- 嵌入式存储设备学习笔记
- 丰富linux驱动内容笔记——platform设备驱动
- 丰富linux驱动内容笔记——platform设备驱动
- platform平台设备学习
- platform平台设备学习
- 我的内核学习笔记2:platform设备模型
- Linux 设备驱动开发 —— platform 设备驱动
- Linux 设备驱动开发 —— platform 设备驱动
- Linux 设备驱动开发 — platform 设备驱动
- platform driver 学习笔记
- 嵌入式linux——学习笔记
- 嵌入式学习笔记3—代码搬移
- 嵌入式linux学习笔记4之字符设备驱动
- ok6410学习笔记(15.platform平台总线驱动模型之混杂设备驱动led)
- linux设备驱动程序学习笔记——主次设备号
- C#/.Net通过Npgsql 访问PostgreSQL 乱码问题解决
- 鼠标滚轮消息WM_MOUSEWHEEL
- 编译external/icu4c/data方法
- RAID的原理基础及linux下软件raid配置
- poj 1091
- 嵌入式学习笔记——platform设备
- 史上最强图标下载,3124个图标专辑,超过60万免费图标提供下载
- python学习笔记之(四)
- 以后还是来这里写博客吧
- 代码分析ADO.NET数据异步处理
- C#中的索引器的简单理解和用法
- Response 弹出js代码的方法
- nginx的proxy_pass和 location为正则表达式的问题
- Tomcat+MySQL的配置(windows下)