win7云主机怎么做网站,绵阳网站建设 经开区,衣服品牌logo大全,网站建设性能分析以下内容源于朱有鹏嵌入式课程的学习与整理#xff0c;如有侵权请告知删除。
前言 之前写到#xff0c;九鼎没有使用内核推荐的LED驱动框架。因此#xff0c;我们打算基于LED驱动框架来编写x210开发板的LED驱动。编写前先要去除九鼎移植的LED驱动#xff0c;然后配置内核支…以下内容源于朱有鹏嵌入式课程的学习与整理如有侵权请告知删除。
前言 之前写到九鼎没有使用内核推荐的LED驱动框架。因此我们打算基于LED驱动框架来编写x210开发板的LED驱动。编写前先要去除九鼎移植的LED驱动然后配置内核支持LED驱动框架最后根据LED驱动框架来编写LED驱动。 一、去除九鼎移植的LED驱动 九鼎移植的驱动在应用层的接口位于/sys/devices/platform/x210-led/目录下有led1、led2、led3、led4四个设备文件各自管理一个led。比如“echo 1 led1”可以点亮其中的led1。 [rootxjh ~]# cd /sys
[rootxjh sys]# ls //sys目录内容
block class devices fs module
bus dev firmware kernel power
[rootxjh sys]# cd devices/
[rootxjh devices]# ls //sys/devices目录内容
platform system virtual
[rootxjh devices]# cd platform/
[rootxjh platform]# ls //sys/devices/platform目录内容
alarm s3c-adc s3c-sdhci.2 s5p-cec
android_pmem.1 s3c-button s3c-sdhci.3 s5p-ehci
arm-pmu.0 s3c-csis s3c-ts s5p-hpd
dm9000.0 s3c-fimc.0 s3c2410-wdt s5p-tvout
pm-wifi s3c-fimc.1 s3c2440-i2c.0 s5pv210-nand
power s3c-fimc.2 s3c2440-i2c.1 s5pv210-uart.0
power.0 s3c-g2d s3c2440-i2c.2 s5pv210-uart.1
pvrsrvkm s3c-jpg s3c24xx-pwm.0 s5pv210-uart.2
reg-s5pv210-pd.0 s3c-keypad s3c24xx-pwm.1 s5pv210-uart.3
reg-s5pv210-pd.1 s3c-mfc s3c24xx-pwm.2 sec-fake-battery
reg-s5pv210-pd.2 s3c-pl330.0 s3c24xx-pwm.3 smdkc110-rtc
reg-s5pv210-pd.3 s3c-pl330.1 s3c64xx-iis.0 soc-audio.1
reg-s5pv210-pd.4 s3c-pl330.2 s3c64xx-iis.1 switch-gpio
reg-s5pv210-pd.5 s3c-sdhci.0 s3c_lcd uevent
regulatory.0 s3c-sdhci.1 s3cfb x210-led //这里
[rootxjh platform]# cd x210-led/
[rootxjh x210-led]# ls // sys/devices/platform/x210-led目录内容
driver led2 led4 power uevent
led1 led3 modalias subsystem
[rootxjh x210-led]# 要去除九鼎移植的LED驱动需要在内核配置阶段去掉相应的选择项然后重新编译得到zImage并烧录至开发板。新内核启动后如果/sys/devices/platform/x210-led目录不存在则说明成功去掉该驱动。 步骤如下内核编译初体验_天糊土的博客-CSDN博客 步骤1在 /home/xjh/iot/embedded_basic/kernel/x210_kernel 执行make distclean、make x210ii_qt_defconfig、make menuconfig。 步骤2在弹出的配置窗口中去除九鼎移植的LED驱动选项。 |………Device Drivers --- |…………Character devices --- |………………[*] x210 led driver //将 * 换成 n。 步骤3在配置窗口中选择支持NFS功能的选项。 见以NFS方式挂载rootfs的设置方法_天糊土的博客-CSDN博客。 可以修改配置文件使得默认设置都是想要的配置这样就不用再进行步骤2与3了。 比如将drivers/char/led目录下的Kconfig文件中的内容修改成如下实测好像不行 config X210_LED_DRIVERbool x210 led driver
# default y 将默认值y改为ndefault nhelpcompile for leddriver,y for kernel,m for module.步骤4执行make得到zImage它在arch/arm/boot目录中。 步骤5将新生成的zImage复制到tftp服务器的目录/tftp开发板启动时uboot会自动从这里下载内核镜像。 步骤6测试/sys/devices/platform/x210-led目录不再存在。 [rootxjh platform]# pwd
/sys/devices/platform
[rootxjh platform]# ls
alarm s3c-adc s3c-sdhci.2 s5p-cec
android_pmem.1 s3c-button s3c-sdhci.3 s5p-ehci
arm-pmu.0 s3c-csis s3c-ts s5p-hpd
dm9000.0 s3c-fimc.0 s3c2410-wdt s5p-tvout
pm-wifi s3c-fimc.1 s3c2440-i2c.0 s5pv210-nand
power s3c-fimc.2 s3c2440-i2c.1 s5pv210-uart.0
power.0 s3c-g2d s3c2440-i2c.2 s5pv210-uart.1
pvrsrvkm s3c-jpg s3c24xx-pwm.0 s5pv210-uart.2
reg-s5pv210-pd.0 s3c-keypad s3c24xx-pwm.1 s5pv210-uart.3
reg-s5pv210-pd.1 s3c-mfc s3c24xx-pwm.2 sec-fake-battery
reg-s5pv210-pd.2 s3c-pl330.0 s3c24xx-pwm.3 smdkc110-rtc
reg-s5pv210-pd.3 s3c-pl330.1 s3c64xx-iis.0 soc-audio.1
reg-s5pv210-pd.4 s3c-pl330.2 s3c64xx-iis.1 switch-gpio
reg-s5pv210-pd.5 s3c-sdhci.0 s3c_lcd uevent
regulatory.0 s3c-sdhci.1 s3cfb //不存在x210-led
[rootxjh platform]# 二、添加LED驱动框架支持 当前内核中没有LED驱动框架表现为/sys/class目录下没有此类因此要添加LED驱动框架支持这主要涉及menuconfig的操作。 1、添加LED驱动框架的步骤 在make menuconfig阶段进行如下配置。 |…………Device Drivers --- |………………[*] LED Support --- |…………………… * LED Class Support 然后重新编译与下载在开发板的/sys/class/目录下将出现leds目录。 [rootxjh ~]# cd /sys/class
[rootxjh class]# ls
backlight i2c-adapter misc regulator scsi_host video4linux
bdi i2c-dev mmc_host rfkill sound vtconsole
block ieee80211 mtd rtc spi_master
firmware input net s3c_bc switch
gpio lcd power_supply scsi_device timed_output
graphics leds //这里 ppp scsi_disk tty
hidraw mem pvr scsi_generic vc
[rootxjh class]# 2、sysfs中的内容分析 三、基于驱动框架写LED驱动具体操作层 1、代码编写前的分析 1可参考的驱动程序在哪里 drivers/leds/leds-s3c24xx.c文件drivers/leds/led-class.c文件 2代码编写的关键点是什么 led_classdev_register函数。 注意在驱动框架核心层drivers/leds/led-class.c文件中已经注册了一个类leds会创建/sys/class/leds这个目录。我们现在要利用驱动框架提供的led_classdev_register函数在/sys/class/leds目录下会创建一个设备。 经过测试不会在/dev下创建设备文件因为这是两条不同的路线。现在的路线是在/sys/class/leds目录下创建一个设备目录目录里有属性文件应用层通过操作这些属性文件进而操作硬件。 2、动手编写代码 这里没有像leds-s3c24xx.c那样使用驱动模型而是参考其中部分内容然后自己编写。 #include linux/module.h // module_init module_exit
#include linux/init.h // __init __exit
#include linux/fs.h
#include linux/leds.h
#include mach/regs-gpio.h
#include mach/gpio-bank.h
#include linux/io.h
#include linux/ioport.h#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DATstatic struct led_classdev mydev; // 定义结构体变量// 这个函数就是要去完成具体的硬件读写任务的
static void s5pv210_led_set(struct led_classdev *led_cdev,\enum led_brightness value)
{printk(KERN_INFO s5pv210_led_set\n);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value LED_OFF){// 用户给了个0希望LED灭writel(0x11111111, GPJ0CON);writel(((13) | (14) | (15)), GPJ0DAT);}else{// 用户给的是非0希望LED亮writel(0x11111111, GPJ0CON);writel(((03) | (04) | (05)), GPJ0DAT);}
}static int __init s5pv210_led_init(void)
{// 用户insmod安装驱动模块时会调用该函数// 该函数的主要任务就是去使用led驱动框架提供的设备注册函数来注册一个设备int ret -1;//填充mydevmydev.name myled;//设备的名字mydev.brightness 255; mydev.brightness_set s5pv210_led_set;ret led_classdev_register(NULL, mydev);if (ret 0) {printk(KERN_ERR led_classdev_register failed\n);return ret;}return 0;
}static void __exit s5pv210_led_exit(void)
{led_classdev_unregister(mydev);
}module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE(GPL); // 描述模块的许可证
MODULE_AUTHOR(aston 1264671872qq.com); // 描述模块的作者
MODULE_DESCRIPTION(s5pv210 led driver); // 描述模块的介绍信息
MODULE_ALIAS(s5pv210_led); // 描述模块的别名信息 3、测试与分析 将上面的驱动程序进行编译然后对比模块安装前后的情况。 [rootxjh ~]# cd /sys/class
[rootxjh class]# ls
backlight i2c-adapter misc regulator scsi_host video4linux
bdi i2c-dev mmc_host rfkill sound vtconsole
block ieee80211 mtd rtc spi_master
firmware input net s3c_bc switch
gpio lcd power_supply scsi_device timed_output
graphics leds ppp scsi_disk tty
hidraw mem pvr scsi_generic vc
[rootxjh class]# cd leds
[rootxjh leds]# ls
mmc0:: mmc1:: mmc2:: mmc3::
[rootxjh leds]# insmod /mnt/module_test.ko
[rootxjh leds]# ls
mmc0:: mmc1:: mmc2:: mmc3:: myled
[rootxjh leds]# cd myled/
[rootxjh myled]# ls
brightness max_brightness power subsystem uevent
[rootxjh myled]# 这测试证明我们写的驱动确实被加载了表现为/sys/class/leds/目录下出现了一个表示设备的文件夹myled这个名字是我们写驱动的时候指定的。 myled文件夹里面有LED硬件的2个属性brightness和max_brightness。 led-class.c文件中有一个led_brightness_show函数和led_brightness_store函数分别对应着用户读与写/sys/class/leds/myled/brightness这个文件时实际执行的代码。当我们在命令行执行“cat brightness”时表示读实际就会执行led_brightness_show函数当我们执行“echo 1 brightness”时表示写实际就会执行led_brightness_store函数。 led_brightness_show函数其实就是读取LED硬件信息然后把硬件信息返回因此该函数会去操控硬件。但是led-class.c文件属于驱动框架中核心层的文件它本身无法直接读取具体硬件因此该函数使用函数指针的方式指向struct led_classdev结构体中相应的读取硬件信息的函数。而struct led_classdev结构体中实际用来读取硬件信息的函数就是我们自己写的驱动文件leds-s5pv210.c中要提供的。同理store函数也是如此。 4、在驱动中将4个LED分开 1机制与策略的含义 驱动只应该提供机制具体实现而不是策略方法、主意、解决方案策略由应用程序来做。 驱动设计时不要对最终需求功能进行假定不能假定用户进行什么操作比如是几个led一起操作还是一个操作而已而应该只是直接的对硬件的操作。 2在驱动中将4个LED分开 驱动层实现对各个LED设备的独立访问并向应用层展示出4个操作接口led1、led2、led3、led4这样应用层可以完全按照自己的需要对LED进行控制。 3代码示例 #include linux/module.h // module_init module_exit
#include linux/init.h // __init __exit
#include linux/fs.h
#include linux/leds.h
#include mach/regs-gpio.h
#include mach/gpio-bank.h
#include linux/io.h
#include linux/ioport.h#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DATstatic struct led_classdev mydev1; // 定义结构体变量
static struct led_classdev mydev2; // 定义结构体变量
static struct led_classdev mydev3; // 定义结构体变量// 这个函数就是要去完成具体的硬件读写任务的
static void s5pv210_led1_set(struct led_classdev *led_cdev, \enum led_brightness value)
{printk(KERN_INFO s5pv210_led1_set\n);writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value LED_OFF){// 用户给了个0希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (13)), GPJ0DAT);}else{// 用户给的是非0希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) ~(13)), GPJ0DAT);}
}static void s5pv210_led2_set(struct led_classdev *led_cdev, \enum led_brightness value)
{printk(KERN_INFO s5pv2102_led_set\n);writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value LED_OFF){// 用户给了个0希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (14)), GPJ0DAT);}else{// 用户给的是非0希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) ~(14)), GPJ0DAT);}
}static void s5pv210_led3_set(struct led_classdev *led_cdev,enum led_brightness value)
{printk(KERN_INFO s5pv210_led3_set\n);writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value LED_OFF){// 用户给了个0希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (15)), GPJ0DAT);}else{// 用户给的是非0希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) ~(15)), GPJ0DAT);}
}static int __init s5pv210_led_init(void)
{// 用户insmod安装驱动模块时会调用该函数// 该函数的主要任务就是去使用led驱动框架提供的设备注册函数来注册一个设备int ret -1;// led1mydev1.name led1;mydev1.brightness 255; mydev1.brightness_set s5pv210_led1_set;ret led_classdev_register(NULL, mydev1);if (ret 0) {printk(KERN_ERR led_classdev_register failed\n);return ret;}// led2mydev2.name led2;mydev2.brightness 255; //这句话就把驱动框架第一部分和第二部分关联起来了mydev2.brightness_set s5pv210_led2_set;ret led_classdev_register(NULL, mydev2);if (ret 0) {printk(KERN_ERR led_classdev_register failed\n);return ret;}// led3mydev3.name led3;mydev3.brightness 255; mydev3.brightness_set s5pv210_led3_set;ret led_classdev_register(NULL, mydev3);if (ret 0) {printk(KERN_ERR led_classdev_register failed\n);return ret;}return 0;
}static void __exit s5pv210_led_exit(void)
{led_classdev_unregister(mydev1);led_classdev_unregister(mydev2);led_classdev_unregister(mydev3);
}module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE(GPL); // 描述模块的许可证
MODULE_AUTHOR(aston 1264671872qq.com); // 描述模块的作者
MODULE_DESCRIPTION(s5pv210 led driver); // 描述模块的介绍信息
MODULE_ALIAS(s5pv210_led); // 描述模块的别名信息