当前位置: 首页 > news >正文

jsp网站开发之html入门知识wordpress 数据库同步

jsp网站开发之html入门知识,wordpress 数据库同步,网站空间服务商,wordpress 恢复主题前言#xff1a; 什么是 Linux 下的 platform 设备驱动 Linux下的字符设备驱动一般都比较简单#xff0c;只是对IO进行简单的读写操作。但是I2C、SPI、LCD、USB等外设的驱动就比较复杂了#xff0c;需要考虑到驱动的可重用性#xff0c;以避免内核中存在大量重复代码 什么是 Linux 下的 platform 设备驱动 Linux下的字符设备驱动一般都比较简单只是对IO进行简单的读写操作。但是I2C、SPI、LCD、USB等外设的驱动就比较复杂了需要考虑到驱动的可重用性以避免内核中存在大量重复代码为此人们提出了驱动的分离与分层的思路演化并诞生出了platform设备驱动。 一、驱动的分层分离 1. 驱动的分离 以I2C接口的三轴加速度传感器为例传统的设备驱动如下图示每个平台都有一个ADXL345的驱动因此设备驱动要重复编写三次。 各平台的主机驱动是不同的但是ADXL345是一样的因此上图可以精简为一个ADXL345驱动和统一的接口API。 实际上除了ADXL345还有AT24C02、MPU6050等I2C设备因此实际的驱动框架图如下示 驱动的分离即将主机驱动和设备驱动分隔开来实际开发中主机驱动一般由半导体厂家提供设备驱动也会由器件厂家写好我们只需要提供设备信息即可。也就是将设备信息从设备驱动中剥离开来设备驱动使用标准方法获取到设备信息然后根据获取到的设备信息来初始化设备 因此驱动只负责驱动设备只负责设备想办法将两者进行匹配即可。这就是Linux中的总线-驱动-设备模型也就是常说的驱动分离 如上图示当向系统注册一个驱动时总线会在右侧的设备中查找看看有没有与之匹配的设备有的话就将两者联系起来当向系统中注册一个设备时总线会在左侧的驱动中查找看有没有与之匹配的驱动有的话也联系起来。 2. 驱动的分层 Linux下的驱动也是分层的分层的目的是为了在不同的层处理不同的内容。以input输入子系统为例input子系统负责管理所有跟输入有关的驱动包括键盘、鼠标、触摸等。 驱动层获取输入设备的原始值获取到的输入事件上报给核心层核心层处理各种IO模型并且提供file_operations操作集合事件层和用户空间进行交互 3. platform平台驱动模型 根据总线-驱动-设备驱动模型IIC、SPI、USB这样实实在在的总线是完全匹配的但是要有一些外设是没法归结为具体的总线比如定时器、RTC、LCD等。为此linux内核创造了一个虚拟的总线platform总线以及platform驱动、platform设备模型。 ①platform总线Linux内核使用bus_type结构体表示总线。 其定义在文件include/linux/device.h中 ②platform驱动platform驱动由platform_driver结构体表示。 此结构体定义在文件include/linux/platform_device.h中。 编写platform驱动时先要定义一个platform_driver结构体变量然后实现结构体中的各个成员变量重点是实现匹配方法以及probe函数。当驱动和设备匹配成功以后probe函数就会执行具体的驱动程序在probe函数里面编写。之后通过以下函数向内核注册platform驱动或卸载platform驱动 ③platform设备platform_device结构体用来表示platform设备。 注意若内核支持设备树的话就无需使用该结构体来描述设备而改用设备树了。该结构体定义在文件include/linux/platform_device.h中在不支持设备树的Linux版本中用户需要编写platform_device变量来描述设备信息然后使用以下函数将设备信息注册到Linux内核中或从内核中注销掉这里我们使用的linux是新版本的了也就直接使用设备树就好了。 二、platform框架分析 1.platform总线注册 和字符型驱动一样我们要使用platform总线之前也需要告诉一下内核也就是注册。使用platform_bus_init函数去进行注册既然要注册那么我们也得告诉内核我们的一些信息。 注册的内容就是 struct bus_type platform_bus_type {.name           platform,.dev_groups   platform_dev_groups,.match           platform_match,.uevent          platform_uevent,.pm        platform_dev_pm_ops,} 对于platform平台而言platform_match函数就是月老负责驱动和设备的匹配。 2.platform驱动 在注册platform驱动之前要定义一个结构体为platform_driver结构体内容为 struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;//- const struct of_device_id    *of_match_table;//- const char             *name;const struct platform_device_id *id_table;bool prevent_deferred_probe;}; 然后使用platform_driver_register函数向内核注册platform驱动。向内核注册platform驱动的时候如果驱动和设备匹配成功最终会执行platform_driver的probe函数。 3.platform设备 1、无设备树的时候此时需要驱动开发人员编写设备注册文件使用platform_device_register函数注册设备。使用platform_device_register函数注册设备也同样需要告诉内核一些注册信息。也就是需要定义个结构体 结构体platform_device struct platform_device {const char *name;int id;bool id_auto;struct device dev;u32 num_resources;struct resource *resource;const struct platform_device_id *id_entry;char *driver_override; /* Driver name to force a match *//* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata archdata; };2有设备树修改设备树的设备节点即可。使用兼容性列表当设备与platform的驱动匹配以后就会执行platform_driver-probe函数。 三、编写 platform 驱动流程 接下来我们就来学习一下如何在设备树下编写 platform 驱动流程 1.在设备树中创建设备节点 由于我们使用的linux是支持设备树的那么毫无疑问我们肯定要先在设备树中创建设备节点来描述设备信息重点是要设置好 compatible 属性的值因为 platform 总线需要通过设备节点的 compatible 属性值来匹配驱动这点要切记。 2、编写platfrom的驱动兼容表 1)建立of_device_id 表也就是驱动的兼容表 static const struct of_device_id leds_of_match[] {{ .compatible atkalpha-gpioled }, /* 兼容属性 */{ /* Sentinel */ }}; 3、建立platform_driver结构体 static struct platform_driver leds_platform_driver {.driver {.name imx6ul-led,.of_match_table leds_of_match,},.probe leds_probe,.remove leds_remove,}; 1设置 platform_driver 中的 of_match_table 匹配表为上面创建的 leds_of_match 2向总线注册驱动的时候会检查当前总线下的所有设备有没有与此驱动匹配的设备如果有的话就执行驱动里面的probe函数。 3卸载驱动的时候会执行驱动里面的remove函数。 4、编写probe函数 函数原型 static int led_probe(struct platform_device *dev); 5、编写remove函数 函数原型 static int led_remove(struct platform_device *dev); 四、实验程序编写 1.在设备树中创建设备节点 2.引入字符设备框架 这里直接引入我们之前写过的字符设备框架在这份驱动的基础上来进行修改如果没有看过之前那篇也没关系下面也会贴出完整代码。 3.编写platfrom的驱动兼容表 /* 匹配列表 */ static const struct of_device_id led_of_match[] {{ .compatible led-gpio },{ /* Sentinel */ } };4.建立platform_driver结构体 /*platform_driver结构体*/ static struct platform_driver led_driver {.driver {.name imx6ul-led,.of_match_table led_of_match,},.probe led_probe,.remove led_remove, }; 5.编写probe函数 当设备和驱动兼容表匹配上的时候就会运行peobe函数 /*当谁列表的设备和驱动匹配上后执行的peobe函数*/ static int led_probe(struct platform_device *dev) {/* 动态注册字符设备的流程一般如下1.调用 alloc_chrdev_region() 函数申请设备编号。2.使用 cdev_init() 函数初始化设备描述结构体。3.使用 cdev_add() 函数将设备号与设备描述结构体关联起来注册字符设备驱动。4.使用 class_create() 函数创建一个设备类.5.使用 device_create() 函数创建一个设备*/int ret 0;/*进入这个函数就表明匹配成功了*/printk(led driver and device was matched!\r\n);/*1 创建设备号根据是否定义了设备号通过条件判断选择不同的创建方式。如果定义了设备号则使用MKDEV宏将主设备号和次设备号合成为设备号并调用register_chrdev_region()函数注册字符设备号。如果没有定义设备号则使用alloc_chrdev_region()函数动态分配设备号并通过MAJOR和MINOR宏获取分配得到的主设备号和次设备号。*/if(gpioled.major){gpioled.devid MKDEV(gpioled.major,0);register_chrdev_region(gpioled.devid,DEVICE_CNT,DEVICE_NAME);}else{alloc_chrdev_region(gpioled.devid,0,DEVICE_CNT,DEVICE_NAME);gpioled.major MAJOR(gpioled.devid);gpioled.minor MINOR(gpioled.devid);}/* 2 初始化cdev设置cdev结构体的拥有者为当前模块THIS_MODULE然后使用 cdev_init() 函数初始化cdev结构体。参数包括待初始化的cdev结构体和用于操作该设备的file_operations结构体hello_drv */gpioled.cdev.owner THIS_MODULE;cdev_init(gpioled.cdev,gpioled_fops);/* 3、添加一个cdev */cdev_add(gpioled.cdev,gpioled.devid,DEVICE_CNT);/*4 创建设备类使用 class_create() 函数创建一个设备类设备类用于在/sys/class目录下创建子目录以组织同一类设备的相关信息。该函数的参数包括所属的模块THIS_MODULE和设备类的名称DEVICE_NAME。如果创建失败IS_ERR() 函数将返回true表示出错此时使用 PTR_ERR() 函数返回错误码。 */gpioled.class class_create(THIS_MODULE,DEVICE_NAME);if(IS_ERR(gpioled.class)){printk(newchr fail!\r\n);return PTR_ERR(gpioled.class);}/*5 创建设备使用 device_create() 函数创建一个设备并在/dev目录下创建相应的设备节点。参数包括设备所属的类newchr.class、父设备NULL如果没有父设备、设备号newchr.devid、设备私有数据NULL一般为设备驱动程序提供一个指针和设备名称DEVICE_NAME。如果创建失败IS_ERR() 函数将返回true表示出错此时使用 PTR_ERR() 函数返回错误码。 */gpioled.device device_create(gpioled.class, NULL, gpioled.devid, NULL, DEVICE_NAME);if(IS_ERR(gpioled.device)){printk(newchr fail!\r\n);return PTR_ERR(gpioled.device);}ret myled_init(gpioled); //初始化ledgpioreturn 0; } 6.编写remove函数 static int led_remove(struct platform_device *dev) {gpio_set_value(gpioled.led_gpio,1);gpio_free(gpioled.led_gpio);printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);/*在模块卸载时使用 cdev_del() 函数注销字符设备驱动并使用 unregister_chrdev_region() 函数释放设备号资源。*//* 注销字符设备驱动 */cdev_del(gpioled.cdev);/* 删除cdev */unregister_chrdev_region(gpioled.devid, DEVICE_CNT); /* 注销设备号 */device_destroy(gpioled.class, gpioled.devid);// 销毁设备删除相应的设备节点class_destroy(gpioled.class);// 销毁设备类释放相关资源printk(gpioled exit!\r\n);return 0; } 完整代码 /**************头文件区域*********************************************************/ #include linux/ide.h #include linux/fs.h #include linux/init.h #include linux/module.h #include linux/cdev.h #include linux/types.h #include linux/kernel.h #include linux/errno.h#include linux/of.h #include linux/of_address.h #include linux/of_gpio.h #include linux/irq.h #include linux/poll.h #include linux/platform_device.h #include linux/fcntl.h#include asm/mach/map.h #include asm/uaccess.h #include linux/io.h /**********************************************************************************//************************函数定义-begin***********************************************/ static int gpioled_release(struct inode *inode, struct file *file); static ssize_t gpioled_read(struct file *file, char __user *buf, size_t size, loff_t *ptr); static ssize_t gpioled_write(struct file *file, const char __user *buf, size_t size, loff_t *ptr); static int gpioled_open(struct inode *inode , struct file *file); static int led_probe(struct platform_device *dev); static int led_remove(struct platform_device *dev); /************************函数定义-end********************************************//************************宏定义-begin***********************************************/ #define DEVICE_NAME dtsplatled #define DEVICE_CNT 1 #define LED_ON 1 #define LED_OFF 0 /************************宏定义-end********************************************//************************结构体定义-begin***********************************************/ /* dtsled设备信息结构体 */ struct dtsled_dev {dev_t devid; /* 设备号 */struct cdev cdev; /* cdev */struct class *class; /* 类 */struct device *device; /* 设备 */int major; /* 主设备号 */int minor; /* 次设备号 */struct device_node *nd; /* 设备节点 */int led_gpio; /* led 所使用的 GPIO 编号 */ }; struct dtsled_dev gpioled; /* led设备 *//* 设备操作函数结构体 */ static const struct file_operations gpioled_fops {.owner THIS_MODULE,.open gpioled_open,.read gpioled_read,.write gpioled_write,.release gpioled_release };/* 匹配列表 */ static const struct of_device_id led_of_match[] {{ .compatible led-gpio },{ /* Sentinel */ } };static struct platform_driver led_driver {.driver {.name imx6ul-led,.of_match_table led_of_match,},.probe led_probe,.remove led_remove, }; /************************结构体定义-end***********************************************//************************file_operations操作函数-begin***********************************************/ static int gpioled_release(struct inode *inode, struct file *file) {printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);return 0; } static ssize_t gpioled_read(struct file *file, char __user *buf, size_t size, loff_t *ptr) {printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);return 0; } static ssize_t gpioled_write(struct file *file, const char __user *buf, size_t size, loff_t *ptr) {int ret;unsigned char databuf[1];unsigned char ledstate;struct dtsled_dev *dev file-private_data;ret __copy_from_user(databuf,buf,size);if(ret 0){return -EFAULT;}ledstate databuf[0];if(ledstate LED_OFF){ gpio_set_value(dev-led_gpio,1);}else if(ledstate LED_ON){gpio_set_value(dev-led_gpio,0);}return 0; } static int gpioled_open(struct inode *inode , struct file *file) {printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);file-private_data gpioled; /* 设置私有数据 */ return 0; } /************************file_operations操作函数-end***********************************************//*****************led初始化函数************************/ static int myled_init(struct dtsled_dev *dev) {int ret 0;/* 1、设置 LED 所使用的 GPIO */ dev-nd of_find_node_by_path(/gpioled);if(dev-nd NULL){printk(gpioled node cant not found!\r\n);return -EINVAL;}else{printk(gpioled node hase been found!\r\n);}/* 2、 获取设备树中的 gpio 属性得到 LED 所使用的 LED 编号 */ dev-led_gpio of_get_named_gpio(dev-nd,gpios,0);if(dev-led_gpio 0){printk(cant get led-gpio\r\n);return -EINVAL;}printk(led-gpio num %d\r\n, dev-led_gpio); /* 3、设置 GPIO1_IO03 为输出并且输出高电平默认关闭 LED 灯 */ ret gpio_request(dev-led_gpio,led0);if(ret 0){printk(led-gpio request fail\r\n); return -EINVAL;}gpio_direction_output(dev-led_gpio,1);return ret; }/************************platfrom操作函数-begin***********************************************/ /*当谁列表的设备和驱动匹配上后执行的peobe函数*/ static int led_probe(struct platform_device *dev) {/* 动态注册字符设备的流程一般如下1.调用 alloc_chrdev_region() 函数申请设备编号。2.使用 cdev_init() 函数初始化设备描述结构体。3.使用 cdev_add() 函数将设备号与设备描述结构体关联起来注册字符设备驱动。4.使用 class_create() 函数创建一个设备类.5.使用 device_create() 函数创建一个设备*/int ret 0;/*进入这个函数就表明匹配成功了*/printk(led driver and device was matched!\r\n);/*1 创建设备号根据是否定义了设备号通过条件判断选择不同的创建方式。如果定义了设备号则使用MKDEV宏将主设备号和次设备号合成为设备号并调用register_chrdev_region()函数注册字符设备号。如果没有定义设备号则使用alloc_chrdev_region()函数动态分配设备号并通过MAJOR和MINOR宏获取分配得到的主设备号和次设备号。*/if(gpioled.major){gpioled.devid MKDEV(gpioled.major,0);register_chrdev_region(gpioled.devid,DEVICE_CNT,DEVICE_NAME);}else{alloc_chrdev_region(gpioled.devid,0,DEVICE_CNT,DEVICE_NAME);gpioled.major MAJOR(gpioled.devid);gpioled.minor MINOR(gpioled.devid);}/* 2 初始化cdev设置cdev结构体的拥有者为当前模块THIS_MODULE然后使用 cdev_init() 函数初始化cdev结构体。参数包括待初始化的cdev结构体和用于操作该设备的file_operations结构体hello_drv */gpioled.cdev.owner THIS_MODULE;cdev_init(gpioled.cdev,gpioled_fops);/* 3、添加一个cdev */cdev_add(gpioled.cdev,gpioled.devid,DEVICE_CNT);/*4 创建设备类使用 class_create() 函数创建一个设备类设备类用于在/sys/class目录下创建子目录以组织同一类设备的相关信息。该函数的参数包括所属的模块THIS_MODULE和设备类的名称DEVICE_NAME。如果创建失败IS_ERR() 函数将返回true表示出错此时使用 PTR_ERR() 函数返回错误码。 */gpioled.class class_create(THIS_MODULE,DEVICE_NAME);if(IS_ERR(gpioled.class)){printk(newchr fail!\r\n);return PTR_ERR(gpioled.class);}/*5 创建设备使用 device_create() 函数创建一个设备并在/dev目录下创建相应的设备节点。参数包括设备所属的类newchr.class、父设备NULL如果没有父设备、设备号newchr.devid、设备私有数据NULL一般为设备驱动程序提供一个指针和设备名称DEVICE_NAME。如果创建失败IS_ERR() 函数将返回true表示出错此时使用 PTR_ERR() 函数返回错误码。 */gpioled.device device_create(gpioled.class, NULL, gpioled.devid, NULL, DEVICE_NAME);if(IS_ERR(gpioled.device)){printk(newchr fail!\r\n);return PTR_ERR(gpioled.device);}ret myled_init(gpioled);#if 0/* 5、设置 LED 所使用的 GPIO */ gpioled.nd of_find_node_by_path(/gpioled);if(gpioled.nd NULL){printk(gpioled node cant not found!\r\n);return -EINVAL;}else{printk(gpioled node hase been found!\r\n);}/* 2、 获取设备树中的 gpio 属性得到 LED 所使用的 LED 编号 */ gpioled.led_gpio of_get_named_gpio(gpioled.nd,gpios,0);if(gpioled.led_gpio 0){printk(cant get led-gpio\r\n);return -EINVAL;}printk(led-gpio num %d\r\n, gpioled.led_gpio); /* 3、设置 GPIO1_IO03 为输出并且输出高电平默认关闭 LED 灯 */ gpio_request(gpioled.led_gpio,led0);gpio_direction_output(gpioled.led_gpio,1); #endifreturn 0; } static int led_remove(struct platform_device *dev) {gpio_set_value(gpioled.led_gpio,1);gpio_free(gpioled.led_gpio);printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);/*在模块卸载时使用 cdev_del() 函数注销字符设备驱动并使用 unregister_chrdev_region() 函数释放设备号资源。*//* 注销字符设备驱动 */cdev_del(gpioled.cdev);/* 删除cdev */unregister_chrdev_region(gpioled.devid, DEVICE_CNT); /* 注销设备号 */device_destroy(gpioled.class, gpioled.devid);// 销毁设备删除相应的设备节点class_destroy(gpioled.class);// 销毁设备类释放相关资源printk(gpioled exit!\r\n);return 0; } /************************platfrom操作函数-endn***********************************************/static int __init gpioled_init(void) {return platform_driver_register(led_driver); }static void __exit gpioled_exit(void) {platform_driver_unregister(led_driver); }module_init(gpioled_init); module_exit(gpioled_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(oudafa); 五   、运行测试 1.编写 Makefile 文件 编写完使用make命令编译驱动程序。 KERN_DIR /home/odf/linux-imx/linux-imxall:clearmake -C $(KERN_DIR) Mpwd modules $(CROSS_COMPILE)gcc -o dtsplatledApp dtsplatledApp.c clean:clearmake -C $(KERN_DIR) Mpwd modules cleanrm -rf modules.orderrm -f dtsplatledAppobj-m dtsplatled.o 2.使用nfs挂载到开发板上。 将编译出来 dtsplatled.ko 和dtsplatledApp 拷贝到 rootfs/lib/modules/4.1.15 目录中 sudo cp dtsplatled.ko dtsplatledApp /home/odf/nfs_rootfs/rootfs/lib/modules/4.1.15/ 驱动模块加载完成以后到/sys/bus/platform/drivers/目录下查看驱动是否存在我们在 dtsplatled.c 中设置 led_driver (platform_driver 类型)的 name 字段为“imx6ul-led”因此会在 /sys/bus/platform/drivers/目录下存在名为“imx6ul-led”这个文件 重启开发板进 入到目录 lib/modules/4.1.15 中输入如下命令加载 dtsplatled.ko 这个驱动模块。 insmod dtsplatled.ko 驱动和模块都存在当驱动和设备匹配成功以后就会输出如图一行语句 3.测试 驱动和设备匹配成功以后就可以测试 LED 灯驱动了输入如下命令打开 LED 灯   ./ledApp /dev/dtsplatled 1 输入如下命令关闭 LED 灯   ./ledApp /dev/dtsplatled 0
http://www.tj-hxxt.cn/news/230138.html

相关文章:

  • 做外贸哪个网站最好什么软件可以自主建设网站
  • 西丽建设网站谷歌浏览器怎么下载
  • 国家示范校建设网站网站页面怎么优化
  • 找设计方案的网站h5商城网站是什么
  • 济宁教育平台网站建设wordpress竖版图片尺寸
  • 做网站图标wordpress图片轮播插件
  • 专门做美食的视频网站有哪些甘肃网站seo技术厂家
  • 当下网站建设网站空间购买流程
  • 淘宝客做的好的几个网站免费qq刷赞网站推广
  • 淘宝客怎么样做自己的网站广西网站建设智能优化
  • 图做的好的网站wordpress置顶文章全文显示
  • wordpress 启用多站点防伪查询网站
  • 数据来源于网站怎么做参考文献延津县建设局网站
  • 网站建设主机类型怎么选html整个页面添加背景图片
  • 北京服饰网站建设网页设计一般尺寸
  • 长泰建设局网站苏州网站建设制作公司
  • 网站开发留言板代码西部数据网站管理助手
  • 做电影网站用什么空间中国建设银行福清分行网站
  • 两个域名同一个网站做优化苏州苏州设计公司
  • 产品导航网站源码wordpress 收不到邮件
  • 关于美食网站的问卷调查怎么做wordpress导入火车头
  • 毕业生对于网站建设感受wordpress 被入侵 删文章
  • 网页设计模板免费网站酒类销售公司的网站建设
  • 建设通网站武义巨合汪志刚厦门网站设计推广公司
  • 潍坊网站维护301网站跳转设置
  • 苏州网站优化公司数据库端口 wordpress
  • 刷数据网站怎么推广网站后台管理系统怎么做
  • 宁波拾谷网站建设app开发公司怎么赚钱的
  • 分类目录网站有哪些网站安全检测方法
  • 有什么网站做统计图的长春网站建设培训