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

dw怎么做别人可以看的网站店面设计招聘

dw怎么做别人可以看的网站,店面设计招聘,拼多多网站怎么建设的,网站 毕业设计代做目录 前言 一、平台设备 二、平台驱动 三、平台驱动简单实例 四、 电源管理 五、udev 和驱动的自动加载 六、使用平台设备的LED 驱动 七、自动创建设备节点 前言 要满足 Linux 设备模型#xff0c;就必须有总线、设备和驱动。但是有的设备并没有对应的物理总线#x…目录 前言 一、平台设备 二、平台驱动 三、平台驱动简单实例 四、 电源管理 五、udev 和驱动的自动加载 六、使用平台设备的LED 驱动 七、自动创建设备节点 前言 要满足 Linux 设备模型就必须有总线、设备和驱动。但是有的设备并没有对应的物理总线比如 LED、RTC 和蜂鸣器等。为此内核专门开发了一种虚拟总线一-platfomm总线用来连接这些没有物理总线的设备或者一些不支持热插拔的设备DM9000 网卡 设备就是挂接在这条总线上的。 一、平台设备 平台设备是用structplatform 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;/* MFD cell pointer */struct mfd_cell *mfd_cell;/*arch specific additions */struct pdev_archdata  archdata; }; 驱动开发者关心的主要成员如下。 name: 设备的名字在平台总线的 match 函数中可用于同平台驱动的匹配 id:设备的ID 号用于区别同类型的不同平台设备。         dev:内的 struct device。         num_resources:平台设备使用的资源个数。         resource: 平台设备的资源列表 (数组)指向资源数组中的首元素. id_entry:用于同平台驱动匹配的 ID,在平台总线的 match 函数中首先尝试匹配该 ID,如果不成功再尝试用 name 成员来匹配。 在平台设备中最关键的就是设备使用的资源信息的描述这是实现设备和驱动分离的关键。struct resource 的定义如下 struct resource {resource_size_t start;resource_size_t end;const char *name;unsigned long flags;struct resource *parent*sibling*child; }; 驱动开发者关心的主要成员如下。         start: 资源的开始对于 IO 内存来说就是起始的内存地址对于中断资源来说就是起始的中断号对于 DMA 资源来说就是起始的 DMA 通道号。         end:资源的结束。         flags:资源的标志定义在“include/linux/ioport.h”文件中最常见的有如下几种. IORESOURCE_MEM:资源的类型是内存资源也包括I/O内存。         IORESOURCE_IRO:资源的类型是中断资源。         IORESOURCE_DMA:资源的类型是 DMA 通道资源。         资源可以组成一个树形结构由成员parent、sibling和child来完成. 平台设备及其资源通常存在于BSP(Board Support Package板级支持包)文件中,该文件通常包含和目标板相关的一些代码。例如对于 QT2410 目标板其对应的 BSP文件为arch/arm/mach-s3c24xx/mach-gt2410.c现将其描述CS8900网卡的平台设备摘录如下。 183 static struct resource qt2410_cs89x0_resources[]{ 184 [0] DEFINE_RES_MEM(0X1900000017) 185 [1] DEFINE_RES_IRQ(IRQ_EINT9), 186 }; 187 188 static struct platform_device qt2410_cs89x0 { 189 .name cirrus-cs89x0 190 .num_resources ARRAY_SIZE(qt2410_cs89x0_resources), 191 .resource qt2410_cs89x0_resources, 192 }; CS8900 平台设备有两个资源分别是 IORESOURCE_MEM 和 IORESOURCE_IRQ两种类型的并用宏 DEFINE_RES_MEM 和 DEFINE_RES_IRQ 来定义。对于 DEFINERES_MEM 宏里面的两个参数分别是内存的起始地址和大小:对于 DEFINE_RES_IRQ宏里面的参数则是中断号。读者可以自行查看这两个宏的定义最终是对 start、end和flags成员进行了赋值。最终定义的平台设备是 qt2410_cs89x0ARRAY_SIZE 是用于获取数组元素个数的宏。 向平台总线注册和注销的平台设备的主要函数如下。 int platform_add_devices(struct platform_device **devs, int num); int platform_device_register(struct platform_device *pdev); void platform_device_unregister(struct platform_device *pdev); platform_add_devices用于一次注册多个平台设备platform_device_register 一次只注册一个平台设备。其实platform_add_devices 是通过多次调用 platform_device_register来实现的。platform_device_unregister 用于注销平台设备。         当平台总线发现有和平台设备匹配的驱动时就会调用平台驱动内的一个函数并传递匹配的平台设备结构地址平台驱动就可以从中获取设备的资源信息。关于资源操作的主要函数如下。   struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num); resource_size_t resource_size(const struct resource *res); platform_get_resource:从平台设备 dev 中获取类型为type、序号为num的资源. resource_size:返回资源的大小其值为 end-start 1。 例如在 CS8900 网卡驱动中就有如下的代码来获取资源及其大小。 1857 mem_res platform_get_resource(pdevIORESOURCE_MEM0); 1858 dev-irq platform_get_irq(pdev0); ...... 1865 lp-size resource_size(mem_res); ...... 1872 virt_addr ioremap(mem_res-startlp-size); 代码第1857行获取了IORESOURCE_MEM资源序号为0。代码第1858 行获取了IORESOURCE_IRQ 资源序号也为0。所以当资源类型不同后序号重新开始编号.代码第1865行获取了内存资源的大小。代码第1872行使用ioremap将内存资源进行映射得到映射后的虚拟地址。 二、平台驱动 平台驱动是用struct 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 platform_device_id *id_table;bool prevent_deferred_probe; }; 驱动开发者关心的主要成员如下。         probe: 总线发现有匹配的平台设备时调用。 remove:所驱动的平台设备被移除时或平台驱动注销时调用。 shutdown、suspend 和 resume: 电源管理函数在要求设备电、挂起和恢复时被调用。内嵌的 struct device_driver 的 pm 成员也有对应的电源管理函数。 id_table: 平台驱动可以驱动的平台设备ID 列表可用于和平台设备匹配。 向平台总线注册和注销的平台驱动的主要函数如下。   platform_driver_register(drv) void platform_driver_unregister(struct platform_driver *); 因为在驱动中经常在模块初始化函数中注册一个平台驱动在清除函数中注销一个平台驱动所以内核定义了一个宏来简化这些代码宏的定义如下。 #define module_platform_driver( __platform_driver) \module_driver(__platform_driver, platform_driver_register\platform_driver_unregister)#define module_driver(__driver, __register, __unregister, ...) \ static int __init_driver##_init(void) \ { \return __register((__driver)##__VA_ARGS__); \ } \ module_init(__driver##_init); static void  __exit __driver##_exit(void) \ { \__unregister((_driver)##_VA_ARGS__); \ } \ module_exit(__driver##_exit); 三、平台驱动简单实例 在前面的基础之上我们可以先来编写一个简单的平台驱动再编写一个模块来注册两个设备代码如下   #include linux/init.h #include linux/kernel.h #include linux/module.h#include linux/platform_device.hstatic void pdev_release(struct device *dev) { }struct platform_device pdev0 {.name pdev,.id 0,.num_resources 0,.resource NULL,.dev {.release pdev_release,}, };struct platform_device pdev1 {.name pdev,.id 1,.num_resources 0,.resource NULL,.dev {.release pdev_release,}, };static int __init pltdev_init(void) {platform_device_register(pdev0);platform_device_register(pdev1);return 0; }static void __exit pltdev_exit(void) {platform_device_unregister(pdev1);platform_device_unregister(pdev0); }module_init(pltdev_init); module_exit(pltdev_exit);MODULE_LICENSE(GPL); MODULE_AUTHOR(name e-mail); MODULE_DESCRIPTION(register a platfom device);#include linux/init.h #include linux/kernel.h #include linux/module.h#include linux/platform_device.hstatic int pdrv_suspend(struct device *dev) {printk(pdev: suspend\n);return 0; }static int pdrv_resume(struct device *dev) {printk(pdev: resume\n);return 0; }static const struct dev_pm_ops pdrv_pm_ops {.suspend pdrv_suspend,.resume pdrv_resume, };static int pdrv_probe(struct platform_device *pdev) {return 0; }static int pdrv_remove(struct platform_device *pdev) {return 0; }struct platform_driver pdrv {.driver {.name pdev,.owner THIS_MODULE,.pm pdrv_pm_ops,},.probe pdrv_probe,.remove pdrv_remove, };module_platform_driver(pdrv);MODULE_LICENSE(GPL); MODULE_AUTHOR(name e-mail); MODULE_DESCRIPTION(A simple platform driver); MODULE_ALIAS(platform:pdev);在 pltdev.c 文件中代码第 7 行至第 29 行分别定义了两个平台设备id为0和1以示区别名字都为 pdev没有使用任何资源。在模块的初始化函数和清除函数中分别注册和注销了这两个平台设备。         在 pltdrv.c 文件中代码第 34 行至第42 行定义了一个平台驱动名字也为pdev,这样才能和平台设备匹配。pm 是电源管理函数的集合实现了挂起和恢复两个电源管理操作。因为是虚拟设备所以并没有做任何电源管理相关的操作。为了简单,probe 和remove函数也只是返回成功而已。代码第44行使用module_platform_driver这个宏来简化模块初始化函数和卸载函数的编写。         编译和测试的命令如下 从上面的测试结果可以看到平台驱动驱动了两个设备 pdev.0 和 pdev.1这是设备名字加过构成的名字。 四、 电源管理 在平台驱动里面实现了挂起和恢复两个电源管理函数从而可以管理设备的电源状态。 /sys/devices/platform/pdev.0/power/control 和 /sys/devices/platform/pdev.1/power/control两个文件可以用来管理两个设备的电源控制方式如果文件的内容为 auto那么设备的电源会根据系统的状态自动进行管理为on则表示打开。我们首先确定电源控制方式为自动可以使用下面的命令进行确认。 貌似只跑一个linux的内核不行捏 没有挂起命令只使用串口貌似也不能挂起那这样的话就还是用ubuntu吧 接下来将 Ubuntu 系统挂起 喵的恢复不了了 试试用vm的挂起能不能起到效果 还是不行下面我修改一下驱动程序看看能不能在挂起后立刻自动恢复   看看上面的选项是不是y并且确定他有唤醒方式 API和版本貌似对不上换一下试试 #include linux/init.h #include linux/kernel.h #include linux/module.h#include linux/platform_device.h #include linux/pm.hstatic int pdrv_suspend(struct device *dev) {printk(pdev: suspend\n);// 在这里添加自动唤醒的代码pm_wakeup_event(dev, 0);printk(pdev: resume\n);return 0; }static int pdrv_resume(struct device *dev) {printk(pdev: resume\n);return 0; }static const struct dev_pm_ops pdrv_pm_ops {.suspend pdrv_suspend,.resume pdrv_resume, };static int pdrv_probe(struct platform_device *pdev) {return 0; }static int pdrv_remove(struct platform_device *pdev) {return 0; }struct platform_driver pdrv {.driver {.name pdev,.owner THIS_MODULE,.pm pdrv_pm_ops,},.probe pdrv_probe,.remove pdrv_remove, };module_platform_driver(pdrv);MODULE_LICENSE(GPL); MODULE_AUTHOR(name e-mail); MODULE_DESCRIPTION(A simple platform driver); MODULE_ALIAS(platform:pdev);我又修改了一下代码 这次没挂起直接关机了 使用命令后挂起成功了但是又是黑屏状态估计哪没配置好 服了这里我环境不行就当成功验证了吧后面我看看怎么修改一下环境或者直接在板子上跑这样很容易恢复。 系统挂起后,再重新恢复系统,使用 dmesg 命令可以看到,驱动中的 suspend 和 resume函数先后都被调用了两次。 # dmesg [ 171.396323] pdev: suspend [ 171.396325] pdev; suspend ...... 176.699954] pdev:resume [ 176.699959] pdev: resume 五、udev 和驱动的自动加载 在上面的例子中我们可以通过加载模块来向系统添加两个设备也可以通过移除模块来删除这两个设备。对于这样的操作我们想使设备被添加到系统后其驱动能够自动被加载这对于实际的可支持热插拔的硬件来说更有必要。比如我们插入一个USB无线网卡那么对应的驱动就应该自动加载而不是由用户来手动加载。要做到这一点,就必须利用到一个工具-udev在入式系统中通常使用 mdev其功能比 udev 要弱很多但也可以移植 udev 到嵌入式系统上。         使用了 Linux 设备模型后任何设备的添加、删除或状态修改都会导致内核向用户空间发送相应的事件这个事件叫 uevent和 kobiect 密切关联。这样用户空间就可以捕获这些事件来自动完成某些操作如自动加载驱动、自动创建和删除设备节点、修改权限、创建软链接、修改网络设备的名字等。目前实现这个功能的工具就是 udev(或 mdev)这是一个用户空间的应用程序捕获来自内核空间发来的事件然后根据其规则文件进行操作。udev的规则文件为/etc/udev/rules.d 目录下后缀为.rules 的文件。         udev 规则文件用#来注释除此之外的就是一条一条的规则。每条规则至少包含一个键值对键分为匹配和赋值两种类型。如果内核发来的事件匹配了规则中的所有匹配键的值那么这条规则就可以得到应用并且赋值键被赋予指定的值。一条规则包含了一个或多个键值对这些键值对用逗号隔开每个键由操作符规定一个操作合法的操作符如下。         和!       :判等用于匹配键。         、和: : 赋值用于赋值键和:的区别是前者允许用新值来覆盖原来的值后者则不允许。则是追加赋值。         常见的键如下。         ACTION:事件动作的名字如add 表示添加         DEVPATH:事件设备的路径。         KERNEL:事件设备的名字。         NAME:节点或网络接口的名字         SUBSYSTEM:事件设备子系统         DRIVER:事件设备驱动的名字。         ENV{key}:设备的属性。         OWNER、GROUP、MODE:设备节点的权限。         RUN:添加一个和设备相关的命令到一个命令列表中。 IMPORT{type):导入一组设备属性的变量依赖于类型 type。 上面的键有的是匹配键有的是赋值键还有的既是匹配键又是赋值键。另外还有很多其他的键在此不一一罗列详细信息请参见 udev 的 man 手册。 值还可以使用?、*和来[]进行通配这和正则表达式中的含义是一样的。接下来来看一个例子。 ACTION--add, SUBSYSTEMscsi_device, RUN/sbin/modprobe sg 它表示当向 SCSI子系统添加任意设备后都要添加一个命令“/sbin/modprobe sg”到命令列表中这个命令就是为相应的设备加载 sg 驱动模块。         在 Ubuntu 中自动加载驱动的规则如下请将这条规则添加到/etc/udev/rules.d/40-modprobe.rules 文件中如果没有这个文件请新建一个。 ENV{MODALIAS}?*RUN/sbin/modprobe $env(MODALIAS} 它表示根据模块的别名信息用 modprobe 命令加载对应的内核模块。为此我们要给平台驱动一个别名如 pltdrv.c 文件中代码的第 49 行。pdev 要和驱动中用于匹配平台设备的名字保持一致。 49 MODULE_ALIAS(platform:pdev); 添加了这一条规则后加载 pltdev 模块就可以自动加载平台 pltdrv 驱动 #IsmodI grep plt # modprobe pltdev #lsmod I grep plt pltdrvpltdev 但是我的ubuntu的modprobe不能用并且开发板还不支持udev所以后面再说。 六、使用平台设备的LED 驱动 前面我们说过之前的驱动最大的问题就是没有把设备和驱动分离开这使得驱动的通用性很差。只要硬件有任何改动(比如换一个管脚增加或删除 LED 灯)都会导致驱动代码的修改。有了 Linux 设备模型以及平台总线后我们可以把设备的信息用平台设备来实现这就大大提高了驱动的通用性。接下来的任务就是把前面的 LED 驱动改造成基于平台总线的设备和驱动。首先是平台设备代码如下   /*fsdev.c*/ #include linux/init.h #include linux/kernel.h #include linux/module.h#include linux/platform_device.hstatic void fsdev_release(struct device *dev) { }static struct resource led2_resources[] {[0] DEFINE_RES_MEM(0x11000C40, 4), };static struct resource led3_resources[] {[0] DEFINE_RES_MEM(0x11000C20, 4), };static struct resource led4_resources[] {[0] DEFINE_RES_MEM(0x114001E0, 4), };static struct resource led5_resources[] {[0] DEFINE_RES_MEM(0x114001E0, 4), };unsigned int led2pin 7; unsigned int led3pin 0; unsigned int led4pin 4; unsigned int led5pin 5;struct platform_device fsled2 {.name fsled,.id 2,.num_resources ARRAY_SIZE(led2_resources),.resource led2_resources,.dev {.release fsdev_release,.platform_data led2pin,}, };struct platform_device fsled3 {.name fsled,.id 3,.num_resources ARRAY_SIZE(led3_resources),.resource led3_resources,.dev {.release fsdev_release,.platform_data led3pin,}, };struct platform_device fsled4 {.name fsled,.id 4,.num_resources ARRAY_SIZE(led4_resources),.resource led4_resources,.dev {.release fsdev_release,.platform_data led4pin,}, };struct platform_device fsled5 {.name fsled,.id 5,.num_resources ARRAY_SIZE(led5_resources),.resource led5_resources,.dev {.release fsdev_release,.platform_data led5pin,}, };static struct platform_device *fsled_devices[] {fsled2,fsled3,fsled4,fsled5, };static int __init fsdev_init(void) {return platform_add_devices(fsled_devices, ARRAY_SIZE(fsled_devices)); }static void __exit fsdev_exit(void) {platform_device_unregister(fsled5);platform_device_unregister(fsled4);platform_device_unregister(fsled3);platform_device_unregister(fsled2); }module_init(fsdev_init); module_exit(fsdev_exit);MODULE_LICENSE(GPL); MODULE_AUTHOR(name e-mail); MODULE_DESCRIPTION(register LED devices);由上可知我们分别定义了 4 个平台设备每一个平台设备代表一个LED 灯之所以要这样做是因为可以任意增加或删除一个 LED 灯。4 个平台设备都有一个IORESOURCE_MEM资源用来描述2个寄存器所占用的内存空间;名字都为 fsled用来和平台驱动匹配;id 分别为 2、3、4、5用来区别不同的设备。还给每个平台设备的platform_data成员赋了值platform_data 的类型是 void*用来向驱动传递更多的信息在这里传递的是每个LED 灯使用的管脚号因为只有I/O内存是不能够控制一个具体的管脚的。这些平台设备放在 fsled_devices 数组中在模块初始化函数中使用platform_add_devices 一次注册到平台总线上。在模块的清除函数中则使用 platform_device_unregister 来注销。         再来看看平台驱动。 fsled.c #include linux/init.h #include linux/kernel.h #include linux/module.h#include linux/fs.h #include linux/cdev.h#include linux/slab.h #include linux/ioctl.h #include linux/uaccess.h#include linux/io.h #include linux/ioport.h #include linux/platform_device.h#include fsled.h#define FSLED_MAJOR 256 #define FSLED_DEV_NAME fsledstruct fsled_dev {unsigned int __iomem *con;unsigned int __iomem *dat;unsigned int pin;atomic_t available;struct cdev cdev; };static int fsled_open(struct inode *inode, struct file *filp) {struct fsled_dev *fsled container_of(inode-i_cdev, struct fsled_dev, cdev);filp-private_data fsled;if (atomic_dec_and_test(fsled-available))return 0;else {atomic_inc(fsled-available);return -EBUSY;} }static int fsled_release(struct inode *inode, struct file *filp) {struct fsled_dev *fsled filp-private_data;writel(readl(fsled-dat) ~(0x1 fsled-pin), fsled-dat);atomic_inc(fsled-available);return 0; }static long fsled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {struct fsled_dev *fsled filp-private_data;if (_IOC_TYPE(cmd) ! FSLED_MAGIC)return -ENOTTY;switch (cmd) {case FSLED_ON:writel(readl(fsled-dat) | (0x1 fsled-pin), fsled-dat);break;case FSLED_OFF:writel(readl(fsled-dat) ~(0x1 fsled-pin), fsled-dat);break;default:return -ENOTTY;}return 0; }static struct file_operations fsled_ops {.owner THIS_MODULE,.open fsled_open,.release fsled_release,.unlocked_ioctl fsled_ioctl, };static int fsled_probe(struct platform_device *pdev) {int ret;dev_t dev;struct fsled_dev *fsled;struct resource *res;unsigned int pin *(unsigned int*)pdev-dev.platform_data;dev MKDEV(FSLED_MAJOR, pdev-id);ret register_chrdev_region(dev, 1, FSLED_DEV_NAME);if (ret)goto reg_err;fsled kzalloc(sizeof(struct fsled_dev), GFP_KERNEL);if (!fsled) {ret -ENOMEM;goto mem_err;}cdev_init(fsled-cdev, fsled_ops);fsled-cdev.owner THIS_MODULE;ret cdev_add(fsled-cdev, dev, 1);if (ret)goto add_err;res platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res) {ret -ENOENT;goto res_err;}fsled-con ioremap(res-start, resource_size(res));if (!fsled-con) {ret -EBUSY;goto map_err;}fsled-dat fsled-con 1;fsled-pin pin;atomic_set(fsled-available, 1);writel((readl(fsled-con) ~(0xF 4 * fsled-pin)) | (0x1 4 * fsled-pin), fsled-con);writel(readl(fsled-dat) ~(0x1 fsled-pin), fsled-dat);platform_set_drvdata(pdev, fsled);return 0;map_err: res_err:cdev_del(fsled-cdev); add_err:kfree(fsled); mem_err:unregister_chrdev_region(dev, 1); reg_err:return ret; }static int fsled_remove(struct platform_device *pdev) {dev_t dev;struct fsled_dev *fsled platform_get_drvdata(pdev);dev MKDEV(FSLED_MAJOR, pdev-id);iounmap(fsled-con);cdev_del(fsled-cdev);kfree(fsled);unregister_chrdev_region(dev, 1);return 0; }struct platform_driver fsled_drv { .driver { .name fsled,.owner THIS_MODULE,}, .probe fsled_probe,.remove fsled_remove, };module_platform_driver(fsled_drv);MODULE_LICENSE(GPL); MODULE_AUTHOR(name e-mail); MODULE_DESCRIPTION(A simple character device driver for LEDs on FS4412 board);fsled.h #ifndef _FSLED_H #define _FSLED_H#define FSLED_MAGIC f#define FSLED_ON _IO(FSLED_MAGIC, 0) #define FSLED_OFF _IO(FSLED_MAGIC, 1)#endif代码第 152 行至第 159 行定义了一个平台驱动 fsled_drv名字叫 fsled和平台设备匹配。代码第 161 行是平台驱动注册和注销的简化宏。         在 fsled_probe 函数中代码第 86 行首先通过 platform_data 取了管脚号。代码第88 行以平台设备中的 id 为次设备号。代码第 93 行动态分配了 struct fsled_dev 结构对象代码第 105行使用 platform_get_resource 获取了I/O内存的资源这样要操作 GPIO管脚的两个信息就都获得了一个是管脚号一个是 I/O 内存地址。代码第 122 行使用platform set_drvdata 将动态分配得到的 fsled 保存到了平台设备中便于之后的代码能从平台设备中获取 struct fsled_dev 结构对象的地址是经常会使用到的一种技巧也是个驱动支持多个设备的关键。         函数 fsled_remove 中使用了 platform_get_drvdata 得到了对应的 struct fsled_dev 结构对象的地址其他操作则是函数 fsled_probe 的反操作。         函数fsled_open 也使用了 container_of宏得到了对应的struct fsled_dev 结构对象的地址并保存在 filp-private_data 中这也是我前面谈到的一个驱动支持多个设备的技巧。         函数 fsled_ioctl 相比于以前则要简单一些因为只控制一个对应的LED灯。         测试的应用代码则是分别打开了 4个 LED 设备文件然后再分别控制代码比较简单这里就不再赘述。测试方法和前面基本一致只是要创建 4 个设备文件用到 4个不同的次设备号 2、3、4、5。 七、自动创建设备节点 前面谈到内核中设备的添加、删除或修改都会向应用层发送热插拔事件应用程序可以捕获这些事件来自动完成某些操作如自动加载驱动、自动创建设备节点等。接下来以mdev为例来说明如何自动创建设备节点。         mdev 创建设备节点有两种方法一种是运行 mdev -s 命令一种是实时捕获热插拔事件。mdev-s 命令通常在根文件系统挂载完成后运行一次它将递归扫描/sys/block 目录和/sys/class 目录下的文件根据文件的内容来调用 make device 自动创建设备文件这在busybox中的 mdev 源码中展现得非常清楚。 int mdev_main(int argc UNUSED_PARAMchar **argv) { ......if (argv[1] strcmp(argv[1]-s) 0) {/** Scan:mdev-s*/ ......recursive_action(/sys/blockACTION_RECURSE | ACTION_FOLLOWLINKS | ACTION_QUIET,fileActiondirAction, temp0);}recursive_action(/sys/classACTION_RECURSE | ACTION_FOLLOWLINKS,fileActiondirActiontemp0); ...... 另外一种情况则是当内核发生了热插拔事件后mdev会自动被调用这体现在根文件系统中的/etc/init.d/reS 初始化脚本文件中。 echo /sbin/mdev /proc/sys/kernel/hotplug 内核有一种在发生热插拔事件后调用应用程序的方式那就是执行/proc/sys/kernel/hotplug 文件中的程序因为这种方式比较简单所以常用在嵌入式系统之中。而之前说的udev 使用的则是 netlink 机制。发生热插拔事件时调用 mdev 程序会将热插拔信息放在环境变量和参数当中mdev 程序利用这些信息就可以自动创建设备节点在 mdev 的源码中也有清晰的体现。 int mdev_main(int argc UNUSED_PARAMchar **argv) { ......env_devname getenv(DEVNAME);/* can be NULL */G.subsystem getenv(SUBSYSTEM);action getenv(ACTION);env_devpath getenv(DEVPATH); ......op index in strings(keywordsaction); ......snprintf(tempPATH_MAX,/sys%s, env_devpath);if (op OP_remove) { ......if (!fw)make_device(env_devname tempop);}else {make_device(env_devname tempop);if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) {if (op OP_add fw)load_firmware(fw temp);}} ...... 上面的代码的总体思路是根据 ACTION 键的值来决定 op 是增加还是移除操作,最终调用 make_device 来自动创建或删除设备节点。 了解了应用层自动创建设备节点的方式后接下来就需要讨论在驱动中如何实现了.既然自动设备节点的创建要依靠热插拔事件和 sysfs 文件系统那这和我们之前讨论的kobjet 就是分不开的mdev 扫描/sys/class 目录暗示我们要创建类并且在类下面应该有具体的设备。为此内核提供了相应的 API。 class_create(ownername)void class_destroy(struct class *cls);struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt...);void device_destroy(struct class *class, dev_t devt); class_create: 创建类owner 是所属的模块对象指针name 是类的名字返回 struct class 对象指针返回值通过IS_ERR 宏来判断是否失败,通过 PTR_ERR 宏来获得错误码。         class_destroy:销毁cls 类。         device_create:在类class 下创建设备parent 是父设备没有则为 NULL。devt 是设备的主次设备号drvdata 是驱动数据没有则为 NULL。fmt 是格式化字符串使用方法类似于printk。         device_destroy:销毁 class 类下面主次设备号为 devt 的设备。返回值的检查方式同class_create。         添加了自动创建设备的驱动的主要代码如下 #include linux/init.h #include linux/kernel.h #include linux/module.h#include linux/fs.h #include linux/cdev.h#include linux/slab.h #include linux/ioctl.h #include linux/uaccess.h#include linux/io.h #include linux/ioport.h #include linux/platform_device.h#include fsled.h#define FSLED_MAJOR 256 #define FSLED_DEV_NAME fsledstruct fsled_dev {unsigned int __iomem *con;unsigned int __iomem *dat;unsigned int pin;atomic_t available;struct cdev cdev;struct device *dev; };struct class *fsled_cls;static int fsled_open(struct inode *inode, struct file *filp) {struct fsled_dev *fsled container_of(inode-i_cdev, struct fsled_dev, cdev);filp-private_data fsled;if (atomic_dec_and_test(fsled-available))return 0;else {atomic_inc(fsled-available);return -EBUSY;} }static int fsled_release(struct inode *inode, struct file *filp) {struct fsled_dev *fsled filp-private_data;writel(readl(fsled-dat) ~(0x1 fsled-pin), fsled-dat);atomic_inc(fsled-available);return 0; }static long fsled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {struct fsled_dev *fsled filp-private_data;if (_IOC_TYPE(cmd) ! FSLED_MAGIC)return -ENOTTY;switch (cmd) {case FSLED_ON:writel(readl(fsled-dat) | (0x1 fsled-pin), fsled-dat);break;case FSLED_OFF:writel(readl(fsled-dat) ~(0x1 fsled-pin), fsled-dat);break;default:return -ENOTTY;}return 0; }static struct file_operations fsled_ops {.owner THIS_MODULE,.open fsled_open,.release fsled_release,.unlocked_ioctl fsled_ioctl, };static int fsled_probe(struct platform_device *pdev) {int ret;dev_t dev;struct fsled_dev *fsled;struct resource *res;unsigned int pin *(unsigned int*)pdev-dev.platform_data;dev MKDEV(FSLED_MAJOR, pdev-id);ret register_chrdev_region(dev, 1, FSLED_DEV_NAME);if (ret)goto reg_err;fsled kzalloc(sizeof(struct fsled_dev), GFP_KERNEL);if (!fsled) {ret -ENOMEM;goto mem_err;}cdev_init(fsled-cdev, fsled_ops);fsled-cdev.owner THIS_MODULE;ret cdev_add(fsled-cdev, dev, 1);if (ret)goto add_err;res platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res) {ret -ENOENT;goto res_err;}fsled-con ioremap(res-start, resource_size(res));if (!fsled-con) {ret -EBUSY;goto map_err;}fsled-dat fsled-con 1;fsled-pin pin;atomic_set(fsled-available, 1);writel((readl(fsled-con) ~(0xF 4 * fsled-pin)) | (0x1 4 * fsled-pin), fsled-con);writel(readl(fsled-dat) ~(0x1 fsled-pin), fsled-dat);platform_set_drvdata(pdev, fsled);fsled-dev device_create(fsled_cls, NULL, dev, NULL, led%d, pdev-id);if (IS_ERR(fsled-dev)) {ret PTR_ERR(fsled-dev);goto dev_err;}return 0;dev_err:iounmap(fsled-con); map_err: res_err:cdev_del(fsled-cdev); add_err:kfree(fsled); mem_err:unregister_chrdev_region(dev, 1); reg_err:return ret; }static int fsled_remove(struct platform_device *pdev) {dev_t dev;struct fsled_dev *fsled platform_get_drvdata(pdev);dev MKDEV(FSLED_MAJOR, pdev-id);device_destroy(fsled_cls, dev);iounmap(fsled-con);cdev_del(fsled-cdev);kfree(fsled);unregister_chrdev_region(dev, 1);return 0; }struct platform_driver fsled_drv { .driver { .name fsled,.owner THIS_MODULE,}, .probe fsled_probe,.remove fsled_remove, };static int __init fsled_init(void) {int ret;fsled_cls class_create(THIS_MODULE, fsled);if (IS_ERR(fsled_cls))return PTR_ERR(fsled_cls);ret platform_driver_register(fsled_drv);if (ret)class_destroy(fsled_cls);return ret; }static void __exit fsled_exit(void) {platform_driver_unregister(fsled_drv);class_destroy(fsled_cls); }module_init(fsled_init); module_exit(fsled_exit);MODULE_LICENSE(GPL); MODULE_AUTHOR(name e-mail); MODULE_DESCRIPTION(A simple character device driver for LEDs on FS4412 board);代码第177行使用class_create 创建了名叫 fsled的类。代码第127行使用device_create在 fsled 类下面创建了 led%d 的设备%d 用平台设备的id 来替代。在创建过程中内核会发送热插拔事件给 mdevmdev 利用这些信息就可以创建设备节点因为设备的名字和设备号都传递给了 device_create而内核又会利用这些参数生成热插拔信息。 使用上面的驱动且驱动加载成功后设备节点就自动被创建了不需要再手动创建.整个测试过程和前面的例子类似这里就不再重复了      #include stdio.h #include stdlib.h #include sys/types.h #include sys/stat.h #include sys/ioctl.h #include fcntl.h #include errno.h#include fsled.hint main(int argc, char *argv[]) {int fd[4];int ret;int num 0;fd[0] open(/dev/led2, O_RDWR);if (fd[0] -1)goto fail;fd[1] open(/dev/led3, O_RDWR);if (fd[1] -1)goto fail;fd[2] open(/dev/led4, O_RDWR);if (fd[2] -1)goto fail;fd[3] open(/dev/led5, O_RDWR);if (fd[3] -1)goto fail;while (1) {ret ioctl(fd[num], FSLED_ON);if (ret -1)goto fail;usleep(500000);ret ioctl(fd[num], FSLED_OFF);if (ret -1)goto fail;usleep(500000);num (num 1) % 4;} fail:perror(led test);exit(EXIT_FAILURE); }测试程序是个流水灯不多说了。 --------------------------------------------------------------------------------------------------------------------------------- 这周感觉更累了已经没有太多的精力继续学习驱动了但是周末我们软件部门聚餐时听着那些四五十的大佬说着人生经历讲着做人道理时我幡然醒悟。一时的强弱代表不了什么态度才是最重要的。只要你有终身学习的态度不会成为不了强者的在公司做工作也是一种学习即便有时做起来不是很愉快但往往向着难受的方向学习才能发展的更加全面。现在来公司已经三周了我刚刚敢叫大家的名字因为大家都是英文花名我是农村的从小英语就不好一直不敢张口叫大家的名字只能尴尬的这个同学那个同学后来发现没人在意你的大概意思对就行了。 以前在学校听说能画四层板的就能找到工作能画六层板就是大佬偶然和硬件部的大佬交流了一下喵的我们公司底板28层我丢啊玩个锤子。晚上吃饭的时候听着大家都是各大名牌大学的研究生。其中不乏浙大这种顶尖学府的人才。顿时一个二本还没毕业的大三学生的我自卑感油然而生。突然萌生了考研的念头。可是真的很讨厌英语。如果以后有机会一定要试试另一种方式读研。去国外读研只需要一封介绍信。但是需要你是某个领域的顶尖人才。我们公司有个华三挖来的大佬。什么都会整个FPGA都是他做的这么多年问题不超过7个或许大家绝对7个很多但是真正工作时你就知道这个含金量了我们软件的问题单貌似有70多个还是10多个人哦。重要的是他还精通python、通信、uboot。其它的我就不了解了一个人可以全方位都牛成为一个架构师我想这是每个专心搞技术的人的最高成就了吧。 我们组有个很阳光的大哥人巨好我们老大太严厉了有时我都不敢问但是这个邻家哥哥一样的同事每次问他东西都给我耐心解决。这周刚好赶上版本验证第一次经历这种大规模代码发布新版本前的验证工作。挺有意思的因为我是实习生可能活少吧大半天就完事了他们几个忙的都见不到人了过了巨无聊的一天第二天他们还在验证我就自己去解决一些新的问题单。其实看着那些署了自己名字的代码进入公司的版本成为其中的一部分还是很有成就感的以后可以吹牛说你用的手机芯片是我写的程序验证出来的啦哈哈。我的老大之前有点不理解他后来吃饭才知道他原来已经结婚了怪不得赚那么多还每天那么节俭在领导面前被迫改变自己的性格。结婚后要学会的第一件事或许就是责任吧。 我还发现了一种名叫领导力和人格魅力的东西。曾经在学校时我在一个大我两届的学长身上见到过。如今在这家公司我又见到了。一个长者大概是公司的二号人物。真的很有人格魅力。有种即便做错了也想跟着他的感觉。 吃完饭去唱歌时玩游戏输了不得不喝了两口酒我根本就不能喝酒吃饭时领导敬酒我都是喝水的有点不好意思哈哈。但是没办法输了就要接受惩罚。有个也是东北的姐姐问到我为什么会来杭州。我楞了一下回了两个字舔狗。是啊北京一个月实习期能拿一万多的不去深圳一个月5000供吃住常州4500管住都没去来了杭州一个月也就4000块还不管吃住。最后呢人家还不是很愿意搭理你不是舔狗又是什么呢。 她并不是很惊艳的那种美丽也没有很好的身材。但是就有一种奇特的魔力吸引我或许是种别样的人格魅力吧。智慧型吸引又或许是因为曾在我最需要帮助时帮了我。呼累。但是说出来舒服了很多。喵的在CSDN写日常不会被和谐吧哈哈。后面技术更扎实了解决问题速度提高后就开始写写小说现在已经看完两千多本了感觉能看下去的很少了所以以后自己写哈哈。就到这里咯以后尽量保证每周更新一篇博客学习些新东西顺便记录一下一周的故事就当是日记了。以后也有可以翻一翻的东西。
http://www.w-s-a.com/news/595905/

相关文章:

  • 山东外贸网站建设怎么样wordpress首页左图右文
  • 志丹网站建设wordpress 形式修改
  • 南通seo网站推广费用网站建设就业前景
  • 自适应网站做mip改造浏览器广告投放
  • 网站meta网页描述网站的推广费用
  • 偃师市住房和城乡建设局网站网站个人主页怎么做
  • 做网站要实名认证吗wordpress去掉仪表盘
  • 在哪做网站好Python建网站的步骤
  • 卢松松的网站办公室设计布局
  • 住房城乡建设干部学院网站织梦网站0day漏洞
  • 企业网站seo优帮云手机桌面布局设计软件
  • 无证做音频网站违法吗智能建站加盟电话
  • 鹿泉专业网站建设做网站为什么要建站点
  • 加强网站建设和维护工作新闻大全
  • 红鱼洞水库建设管理局网站左右左布局网站建设
  • 手机网站建设地址做网站公
  • 贵州建设厅网站首页网络公司除了做网站
  • 运动鞋建设网站前的市场分析wordpress 搜索框代码
  • app开发网站开发教程平台网站开发的税率
  • 百度网站优化排名加强服务保障满足群众急需i
  • 宁夏建设职业技术学院网站安徽网站优化建设
  • 四川关于工程建设网站硬盘做网站空间
  • 桂林网站制作培训学校外包seo公司
  • 莱州网站建设方案北京装修公司口碑
  • 大型网站建设济南兴田德润团队怎么样韩国女足出线了吗
  • 南通做网站找谁重庆网络推广网站推广
  • ps网站主页按钮怎么做怎样做网站的用户分析
  • 哪个网站做黑色星期五订酒店活动公司网络营销推广软件
  • 岳阳新网网站建设有限公司网页设计基础考试题目
  • 辽宁响应式网站费用海外平台有哪些