Linux 2.6 device model2
linux的bus、device、driver介绍
linux的bus、device、driver介绍 linux 通过device和driver分别管理系统中的设备和驱动,⽤bus将设备和驱动关联起来,bus可以看成是设备和驱动的媒介,可以匹配设备和驱动。
这样设备和驱动可以独⽴加载,互不影响。
sysfs是⼀个基于内存的⽂件系统,它的作⽤是将内核信息以⽂件的⽅式提供给⽤户程序使⽤。
我们都知道设备和对应的驱动都是由内核管理的,这些对于⽤户空间是不可见的。
现在通过sysfs,可以在⽤户空间直观的了解设备驱动的层次结构。
⼀、bus注册过程bus_type结构体代表⼀条总线,如下所⽰:struct bus_type {const char *name; //名称const char *dev_name;struct device *dev_root;struct device_attribute *dev_attrs; /* use dev_groups instead */const struct attribute_group **bus_groups;const struct attribute_group **dev_groups;const struct attribute_group **drv_groups;int (*match)(struct device *dev, struct device_driver *drv); //device和driver的匹配函数int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;const struct iommu_ops *iommu_ops;struct subsys_private *p; struct lock_class_key lock_key;};struct subsys_private {struct kset subsys; //对应/sys/bus⽬录struct kset *devices_kset; //对应/sys/bus/devices⽬录struct list_head interfaces;struct mutex mutex;struct kset *drivers_kset; //对应/sys/bus/drivers⽬录struct klist klist_devices; //该bus下的所有devicestruct klist klist_drivers; //该bus下的所有driverstruct blocking_notifier_head bus_notifier;unsigned int drivers_autoprobe:1;struct bus_type *bus;struct kset glue_dirs;struct class *class;};向系统添加⼀条bus_type总线时,改总线会⾃动添加到/sys/bus⽬录下,bus⽬录是系统⾃动创建的,这个bus⽬录为static struct kset *bus_kset,定义在kernel/drivers/base/bus.c中。
linux驱动模型
我们将详细的介绍Linux的设备驱动模型。
Linux设备驱动模型是一个相当复杂的系统,对于初学者来说真有些无从入手。
而且更加困难的是,随着新的Linux Kernel的release,Linux 的设备驱动模型总会有或大或小的变化,我们将尽量展现Linux Kernel 的这种变化。
早期的Linux内核(版本2.4之前)并没有实现一个统一的设备模型,设备节点的创建一般是mknod命令手动创建或利用devfs文件系统创建。
早期的Linux发行版一般会采用手动创建的方式预先把通常用到的节点都创建出来,而嵌入式系统则会采用devfs的方式。
起初Linux 2.6 内核还支持devfs,但从2.6.18开始,内核完全移除了devfs系统而采用的udev的方式动态的创建设备节点。
因此,新的Linux发行版都采用udev的方式管理设备节点文件。
Linux2.6设备驱动模型的基本元素是Class、Bus、Device、Driver,下面我们分别介绍各个部分。
Class 和Class Device驱动模型最基本的概念是设备及其类别,Linux中使用struct class 和struct class_device来管理不同类别的设备。
由于设备驱动模型是一个复杂的系统,我们还是从一个简单的例子开始介绍,然后在逐步展开。
其实实现设备节点的动态创建是一个很简单的事情,并不需要太多的代码。
我们修改我们的驱动初始化函数如下:#include <linux/device.h>#define DEVNAME "hello"static dev_t dev;static struct class *hello_c lass;static struct cdev *hello_cdev;static int __init hello_init(void){int error;error = alloc_chrdev_region(&dev, 0, 2, "hello");if (error){printk("hello: alloc_chardev_region failed! ");goto out;}hello_cdev = cdev_alloc();if (hello_cdev == NULL){printk("hello: alloc cdev failed! ");error = -ENOMEM;goto out_chrdev;}hello_cdev->ops = &hello_fops;hello_cdev->owner = THIS_MODULE;error = cdev_add(hello_cdev, dev, 1);if (error){printk("hello: cdev_add failed! ");goto out_cdev;}hello_class = class_create(THIS_MODULE, DEVNAME);if (IS_ERR(hello_class)){error = PTR_ERR(hello_class);goto out_chrdev;}class_device_create(hello_class, NULL, dev, NULL, DEVNAME);memset (hello_buf, 0, sizeof(hello_buf));memcpy(hello_buf, DEFAULT_MSG, sizeof(DEFAULT_MSG));printk("hello: Hello World! ");return 0;out_cdev:cdev_del(hello_cdev);out_chrdev:unregister_chrdev_region(hello_cdev->dev, 2);out:return error;}static void __exit hello_exit(void){class_device_destroy(hello_class, dev);class_destroy(hello_class);unregister_chrdev_region(hello_cdev->dev, 2);cdev_del(hello_cdev);printk("hello: Goodbye World ");}重新编译这个驱动程序,当加载这个驱动到内核中时,系统(一般是hotplug和udev系统)就会自动的创建我们指定的设备名字:/dev/hello,同时,你也可以发现在sysfs系统中添加了新的文件:/sys/class/hello/hello/。
linux 模拟硬件拔插的命令
linux 模拟硬件拔插的命令Linux模拟硬件拔插的命令在日常的Linux系统管理和维护中,经常会遇到需要模拟硬件拔插的情景。
这些情景可能是为了测试硬件设备的可靠性、检测驱动程序的兼容性,亦或是进行系统的故障排查。
本文将一步一步地回答关于Linux模拟硬件拔插的命令,并提供一些实例来帮助读者更好地理解。
1. Linux设备模拟工具简介在Linux系统中,可以使用一些设备模拟工具来模拟硬件的插拔操作。
这些工具可以模拟多种硬件设备,如USB设备、网卡、串口等,并提供与真实硬件设备一样的操作体验。
下面我们将介绍一些常用的设备模拟工具。
1.1 USB\_GADGETUSB\_GADGET是一个支持模拟USB设备的框架,可以用于在Linux设备上模拟USB设备插拔的操作。
它通过创建一个虚拟设备并将其绑定到相应的USB总线上来实现设备模拟。
使用USB\_GADGET需要在内核配置文件中启用相应的选项,并在系统启动时加载相应的内核模块。
一旦虚拟设备创建成功,可以通过向特定的配置文件写入命令来模拟设备的插拔。
1.2 EEMulatorEEMulator是一个开源的USB模拟器,支持模拟多种USB设备,如鼠标、键盘、摄像头等。
它可以通过虚拟机、容器、实体主机等多种方式运行,并提供与真实设备相同的输入输出接口。
EEMulator可以帮助开发人员测试其软件的USB设备兼容性,并提供了丰富的API和命令行工具以便进行设备模拟。
1.3 QEMUQEMU是一款开源的虚拟机监控器,可以模拟多种硬件平台的设备。
它支持通过命令行或图形界面进行设备模拟,并可模拟多种虚拟硬件设备,如网卡、声卡、USB等。
QEMU提供了灵活的配置选项,可以根据需要来进行设备模拟,并支持多种虚拟硬盘和光驱格式。
2. 使用USB\_GADGET模拟硬件插拔USB\_GADGET是一种内核模块,可用于模拟USB设备的插拔操作。
以下是一些使用USB\_GADGET模拟硬件插拔的实例。
Linux命令行中的硬件信息查看和驱动管理
Linux命令行中的硬件信息查看和驱动管理在Linux命令行中,我们可以通过一些命令来查看硬件信息和管理驱动,这对于系统维护和故障排除非常重要。
本文将介绍几个常用的命令及其用法,帮助您快速获取硬件信息和管理驱动。
1. 查看硬件信息1.1 lshw命令lshw(或者lswhw)是一个用于查看硬件信息的命令,可以列出系统中所有硬件的详细信息,包括处理器、内存、硬盘、网卡等。
使用示例:```$ sudo lshw```运行以上命令后,您将看到完整的硬件信息列表,可以通过滚动查看或者使用管道和grep命令过滤感兴趣的部分。
1.2 lspci命令lspci命令用于列出系统中所有PCI设备的信息,包括显卡、网卡、声卡等。
使用示例:```$ lspci```该命令会输出PCI设备的详细信息,可以通过管道和grep进行过滤。
1.3 lsusb命令lsusb命令用于列出系统中所有USB设备的信息。
使用示例:```$ lsusb```该命令会输出USB设备的详细信息,可以通过管道和grep进行过滤。
2. 管理驱动2.1 modprobe命令modprobe命令用于加载和卸载Linux内核模块,包括驱动程序。
使用示例:```$ sudo modprobe <module_name> // 加载模块$ sudo modprobe -r <module_name> // 卸载模块```其中,`<module_name>`为要加载或卸载的模块名称。
2.2 lsmod命令lsmod命令用于列出当前已加载的内核模块。
使用示例:```$ lsmod```该命令会输出已加载模块的列表,包括模块名称、使用次数等信息。
2.3 rmmod命令rmmod命令用于卸载已加载的内核模块。
使用示例:```$ sudo rmmod <module_name>```其中,`<module_name>`为要卸载的模块名称。
Linux2.6内核移植系列教程
Linux2.6内核移植系列教程第一:Linux 2.6内核在S3C2440平台上移植此教程适合2.6.38之前的版本,其中2.6.35之前使用同一yaffs补丁包,2.6.36--2.6.28 yaffs文件系统有所改变,2.6.39之后的暂时不支持,源码下载请到:/1.解压linux-2.6.34.tar.bz2源码包#tar jxvf linux-2.6.34.tar.bz22.修改linux-2.6.34/Makefile文件,在makefile中找到以下两条信息并做修改ARCH ? =armCROSS_COMPILE?=/usr/local/arm/4.3.2/bin/arm-linux-注意:交叉编译器的环境变量也需要改为4.3.2#export PATH=/usr/local/arm/4.3.2/bin/:$PATH其中ARCH变量用来决定:配置、编译时读取Linux源码arch目录下哪个体系结构的文件PATH 用来决定交叉编译器版本3.修改机器类型ID号Linux源码中支持多种平台的配置信息,内核会根据bootloader传进来的mach-types决定那份平台的代码起作用,本人手里的板子是仿照三星公司官方给出的demo板改版而来,所以采用arch/arm/mach-s3c2440/mach-smdk2440.c此配置文件,打开此文件,翻到最后,有以下信息:MACHINE_START(S3C2440, "SMDK2440")/* Maintainer: Ben Dooks <ben@> */.phys_io= S3C2410_PA_UART,.io_pg_offst= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,.boot_params= S3C2410_SDRAM_PA + 0x100,.init_irq= s3c24xx_init_irq,.map_io= smdk2440_map_io,.init_machine= smdk2440_machine_init,.timer= &s3c24xx_timer,MACHINE_ENDMACHINE_START(S3C2440, "SMDK2440")决定了此板子的mach-types,可以在以下文件中找到S3C2440对应的具体数字,"arch/arm/tools/mach-types"文件查找S3C2440,362,这里刚好与我们的bootloader相同,所以不用做修改,直接保存退出即可,如果不同则根据bootloader的内容修改此文件,或根据此文件修改boorloader的内容(在vivi中可通过param show查看,u-boot在Y:\test\u-boot_src\u-boot_edu-2010.06\board\samsung\unsp2440\unsp2440.c文件:gd->bd->bi_arch_number = MACH_TYPE_S3C2440;中决定)。
基于Linux设备模型的单总线接口的设计
基于Linux设备模型的单总线接口的设计王龙奇;樊明辉;陈丽红【摘要】1-Wire Bus is a bus protocol which connects some sensors and low-speed devices with the host,such as the smart temperature sensor DS18B20,A/D chip,and so on. With the development of the internet of things,the ap-plication of these sensors will become more widespread,but their interfaces are not closely linked with the kernel, the kernel can not unify the management,so stability and reliability may not be guaranteed. In line with the premise of the Linux kernel device model,a stable 1-Wire interface is given. the controller will be divided into three parts, top-level device interface, the core layer and the underlying hardware interface;menuwhile the driver and the device,the top-level device interface and the specific hardware are seperated in operations.%单总线是一些传感器和低速器件与主机通信常用一种总线协议,如智能温度传感器DS18B20,A/D转换芯片等。
嵌入式Linux2.6内核启动流程)
Linux内核形成之阳早格格创做(国嵌)L1.解压缩2.初初化3.开用应用步调Linux内核开用过程(国嵌)—控造解压缩)Start:.type start,#function.rept 8mov r0, r0.endrb 1f.word 0x016f2818 @ Magic numbers to help the loader.word start @ absolute load/run zImage address.word _edata @ zImage end address1: mov r7, r1 @ save architecture ID mov r8, r2 @ save atags pointer那也标记着u-boot将系统真足的接给了OS,bootloader死命终止.之后代码正在133止会读与cpsr并推断是可处理器处于supervisor模式——从u-boot加进kernel,系统已经处于SVC32模式;而利用angel加进则处于user模式,还需要特殊二条指令.之后是再次确认中断关关,并完成cpsr 写进mrs r2, cpsr @ get current modetst r2, #3 @ not user?bne not_angelmov r0, #0x17 @ angel_SWIreason_EnterSVCswi 0x123456 @ angel_SWI_ARMnot_angel:mrs r2, cpsr @ turn off interrupts toorr r2, r2, #0xc0 @ prevent angel from runningmsr cpsr_c, r2而后正在LC0天点处将分段疑息导进r0-r6、ip、sp等寄存器,并查看代码是可运止正在与链接时相共的目标天点,以决断是可举止处理.由于目前很罕见人不使用loader战tags,将zImage烧写到rom间接从0x0位子真止,所以那个处理是必须的(然而是zImage的头目前也死存了不必loader也可开用的本领).arm架构下自解压头普遍是链接正在0x0天点而被加载到0x30008000运止,所以要建正那个变更.波及到r5寄存器存搁的zImage基天点r6战r12(即ip寄存器)存搁的got(global offset table)r2战r3存搁的bss段起止天点sp栈指针天点很简朴,那些寄存器统统被加上一个您也能猜到的偏偏移天点0x30008000.该天点是s3c2410相关的,其余的ARM 处理器不妨参照下表PXA2xx是0xa0008000IXP2x00战IXP4xx是0x00008000TI davinci DM64xx是0x80008000TI omap系列是0x80008000AT91RM/SAM92xx系列是0x20008000Cirrus EP93xx是0x00008000那些收配爆收正在代码172止开初的场合,底下只粘揭一部分add r5, r5, r0add r6, r6, r0add ip, ip, r0后里正在211止举止bss段的浑整处事not_relocated: mov r0, #01: str r0, [r2], #4 @ clear bssstr r0, [r2], #4str r0, [r2], #4str r0, [r2], #4cmp r2, r3blo 1b而后224止,挨开cache,并为后里解压缩树立64KB的临时malloc空间bl cache_onmov r1, sp @ malloc space above stack add r2, sp, #0x10000 @ 64k max 接下去238止举止查看,决定内核解压缩后的Image目标天点是可会覆盖到zImage头,如果是则准备将zImage头变化到解压出去的内核后里cmp r4, r2bhs wont_overwritesub r3, sp, r5 @ > compressed kernel size add r0, r4, r3, lsl #2 @ allow for 4x expansion cmp r0, r5bls wont_overwritemov r5, r2 @ decompress after mallocspacemov r0, r5mov r3, r7bl decompress_kernel真正在情况——正在大普遍的应用中,内核编译皆市把压缩的zImage战非压缩的Image链接到共样的天点,s3c2410仄台下即是0x30008000.那样干的佳处是,人们不必体贴内核是Image仍旧zImage,搁到那个位子真止便OK,所以正在解压缩后zImage头必须为真真的内核让路.正在250止解压完成,内核少度返回值存搁正在r0寄存器里.正在内核开端空出128字节的栈空间用,而且使其少度128字节对于齐.add r0, r0, #127 + 128 @ alignment + stackbic r0, r0, #127 @ align the kernel length 算出搬移代码的参数:估计内核开端天点并存搁于r1寄存器,需要搬移代码本去天点搁正在r2,需要搬移的少度搁正在r3.而后真止搬移,并树立佳sp指针指背新的栈(本去的栈也会被内核覆盖掉)add r1, r5, r0 @ end of decompressed kerneladr r2, reloc_startldr r3, LC1add r3, r2, r31: ldmia r2!, {r9 - r14} @ copy relocation code stmia r1!, {r9 - r14}ldmia r2!, {r9 - r14}stmia r1!, {r9 - r14}cmp r2, r3blo 1badd sp, r1, #128 @ relocate the stack搬移完成后刷新cache,果为代码天点变更了不克不迭让cache再掷中被内核覆盖的老天点.而后跳转到新的天点继承真止bl cache_clean_flushadd pc, r5, r0 @ call relocation code注意——zImage正在解压后的搬移战跳转会给gdb调试内核戴去贫苦.果为用去调试的标记表是正在编译是死成的,本去不知讲以去会被搬移到那边去,惟有正在内核解压缩完成之后,根据估计出去的参数“报告”调试器那个变更.以撰写本文时使用的zImage为例,内核自解压头沉定背后,reloc_start天点由0x30008360形成0x30533e60.故咱们要把vmlinux的标记表也相映的从0x30008000后移到0x30533b00开初,那样gdb便不妨精确的对于应源代码战呆板指令.随着头部代码移动到新的位子,不会再战内核的目标天点辩论,不妨开初内核自己的搬移了.此时r0寄存器存搁的是内核少度(庄重的道是少度中加128Byte的栈),r4存搁的是内核的手段天点0x30008000,r5是暂时内核存搁天点,r6是CPU ID,r7是machine ID,r8是atags天点.代码从501止开初reloc_start: add r9, r5, r0sub r9, r9, #128 @ do not copy the stackdebug_reloc_startmov r1, r41:.rept 4ldmia r5!, {r0, r2, r3, r10 - r14} @ relocate kernelstmia r1!, {r0, r2, r3, r10 - r14}.endrcmp r5, r9blo 1badd sp, r1, #128 @ relocate the stack接下去正在516止扫除并关关cache,浑整r0,将machine ID存进r1,atags指针存进r2,再跳进0x30008000真止真真的内核Imagecall_kernel: bl cache_clean_flushbl cache_offmov r0, #0 @ must be zeromov r1, r7 @ restore architecture numbermov r2, r8 @ restore atags pointermov pc, r4 @ call kernel内核代码出心正在arch/arm/kernel/head.S文献的83止.最先加进SVC32模式,并查询CPU ID,查看合法性msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode@ and irqs disabledmrc p15, 0, r9, c0, c0 @ get processor idbl __lookup_processor_type @ r5=procinfo r9=cpuid movs r10, r5 @ invalid processor (r5=0)? beq __error_p @ yes, error 'p'接着正在87前进一步查询machine ID并查看合法性bl __lookup_machine_type @ r5=machinfomovs r8, r5 @ invalid machine (r5=0)? beq __error_a @ yes, error 'a'其中__lookup_processor_type正在linux-2.6.24-moko-linuxbj/arch/arm/kernel/head-common.S文献的149止,该函数尾将标号3的本质天点加载到r3,而后将编译时死成的__proc_info_begin假造天点载进到r5,__proc_info_end 假造天点载进到r6,标号3的假造天点载进到r7.由于adr 真指令战标号3的使用,以及__proc_info_begin等标记正在linux-2.6.24-moko-linuxbj/arch/arm/kernel/vmlinux.lds 而不是代码中被定义,此处代码不利害常曲瞅,念弄领会代码缘由的读者请耐性阅读那二个文献战adr真指令的证明.r3战r7分别死存的是共一位子标号3的物理天点(由于不开用mmu,所以目前肯定是物理天点)战假造天点,所以女者相减即得到假造天点战物理天点之间的offset.利用此offset,将r5战r6中死存的假造天点转化成物理天点__lookup_processor_type:adr r3, 3fldmda r3, {r5 - r7}sub r3, r3, r7 @ get offset between virt&physadd r5, r5, r3 @ convert virt addresses toadd r6, r6, r3 @ physical address space而后从proc_info中读出内核编译时写进的processor ID战之前从cpsr中读到的processor ID对于比,查看代码战CPU硬件是可匹配(念正在arm920t上运止为cortex-a8编译的内核?不让!).如果编译了多种处理器收援,如versatile板,则会循环每种type依次考验,如果硬件读出的ID正在内核中找不到匹配,则r5置0返回1:ldmiar5, {r3, r4}@ value, maskandr4, r4, r9@ mask wanted bitsteqr3, r4beq2faddr5, r5, #PROC_INFO_SZ@ sizeof(proc_info_list)cmpr5, r6blo1bmovr5, #0@ unknown processor2:movpc, lr__lookup_machine_type正在文献的197止,编码要领与查看processor ID真足一般,请参照前段__lookup_machine_type:adrr3, 3bldmiar3, {r4, r5, r6}subr3, r3, r4@ get offset between virt&physaddr5, r5, r3@ convert virt addresses toaddr6, r6, r3@ physical address space1:ldrr3, [r5, #MACHINFO_TYPE]@ get machine typeteqr3, r1@ matches loader number?beq2f@ foundaddr5, r5, #SIZEOF_MACHINE_DESC@ nextmachine_desccmpr5, r6blo1bmovr5, #0@ unknown machine2:movpc, lr代码回到head.S第92止,查看atags合法性,而后创造初初页表bl__vet_atagsbl__create_page_tables创造页表的代码正在218止,最先将内核起初天点-0x4000到内核起初天点之间的16K死存器浑0__create_page_tables:pgtblr4@ page table address/** Clear the 16K level 1 swapper page table*/movr0, r4movr3, #0addr6, r0, #0x40001:strr3, [r0], #4strr3, [r0], #4strr3, [r0], #4strr3, [r0], #4teqr0, r6bne1b而后正在234止将proc_info中的mmu_flags加载到r7ldrr7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags正在242止将PC指针左移20位,得到内核第一个1MB空间的段天点存进r6,正在s3c2410仄台该值是0x300.接着根据此值存进映射标记movr6, pc, lsr #20@ start of kernel sectionorrr3, r7, r6, lsl #20@ flags + kernel basestrr3, [r4, r6, lsl #2]@ identity mapping完成页表树立后回到102止,为挨开假造天点映射做准备.树立sp指针,函数返回天点lr指背__enable_mmu,并跳转到linux-2.6.24-moko-linuxbj/arch/arm/mm/proc-arm920.S的386止,扫除I-cache、D-cache、write buffer 战TLB__arm920_setup:movr0, #0mcrp15, 0, r0, c7, c7@ invalidate I,D caches on v4mcrp15, 0, r0, c7, c10, 4@ drain write buffer on v4#ifdef CONFIG_MMUmcrp15, 0, r0, c8, c7@ invalidate I,D TLBs on v4#endif而后返回head.S的158止,加载domain战页表,跳转到__turn_mmu_on__enable_mmu:#ifdef CONFIG_ALIGNMENT_TRAPorrr0, r0, #CR_A#elsebicr0, r0, #CR_A#endif#ifdef CONFIG_CPU_DCACHE_DISABLEbicr0, r0, #CR_C#endif#ifdef CONFIG_CPU_BPREDICT_DISABLEbicr0, r0, #CR_Z#endif#ifdef CONFIG_CPU_ICACHE_DISABLEbicr0, r0, #CR_I#endifmovr5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \domain_val(DOMAIN_KERNEL,DOMAIN_MANAGER) | \domain_val(DOMAIN_TABLE, DOMAIN_MANAGER)| \domain_val(DOMAIN_IO, DOMAIN_CLIENT))mcrp15, 0, r5, c3, c0, 0@ load domain access registermcrp15, 0, r4, c2, c0, 0@ load page table pointerb__turn_mmu_on正在194止把mmu使能位写进mmu,激活假造天点.而后将本去死存正在sp中的天点载进pc,跳转到head-common.S的__mmap_switched,至此代码加进假造天点的天下movr0, r0mcrp15, 0, r0, c1, c0, 0@ write control regmrcp15, 0, r3, c0, c0, 0@ read id regmovr3, r3movr3, r3movpc, r13正在的37止开初扫除内核bss段,processor ID死存正在r9,machine ID报存留r1,atags天点死存正在r2,并将统造寄存器死存到r7定义的内存天点.接下去跳进linux-2.6.24-moko-linuxbj/init/main.c的507止,start_kernel函数.那里只粘揭部分代码(第一个C谈话函数,做一系列的初初化)__mmap_switched:adrr3, __switch_data + 4ldmiar3!, {r4, r5, r6, r7}cmpr4, r5@ Copy data segment if needed1:cmpner5, r6ldrnefp, [r4], #4strnefp, [r5], #4bne1basmlinkage void __init start_kernel(void){char * command_line;extern struct kernel_param __start___param[], __stop___param[];smp_setup_processor_id();/** Need to run as early as possible, to initialize the* lockdep hash:*/lockdep_init();debug_objects_early_init();cgroup_init_early();local_irq_disable();early_boot_irqs_off();early_init_irq_lock_class();/** Interrupts are still disabled. Do necessary setups, then* enable them*/lock_kernel();tick_init();boot_cpu_init();page_address_init();printk(KERN_NOTICE);printk(linux_banner);setup_arch(&command_line);mm_init_owner(&init_mm, &init_task);setup_command_line(command_line);setup_per_cpu_areas();setup_nr_cpu_ids();smp_prepare_boot_cpu();/* arch-specific boot-cpu hooks */ /** Set up the scheduler prior starting any interrupts (such as the* timer interrupt). Full topology setup happens at smp_init() * time - but meanwhile we still have a functioning scheduler. *//** Disable preemption - early bootup scheduling is extremely * fragile until we cpu_idle() for the first time.*/preempt_disable();build_all_zonelists();page_alloc_init();printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);parse_early_param();parse_args("Booting kernel", static_command_line, __start___param,__stop___param - __start___param,&unknown_bootoption);if (!irqs_disabled()) {printk(KERN_WARNING "start_kernel(): bug: interrupts were ""enabled *very* early, fixing it\n");local_irq_disable();}sort_main_extable();rcu_init();/* init some links before init_ISA_irqs() */early_irq_init();init_IRQ();pidhash_init();init_timers();hrtimers_init();softirq_init();timekeeping_init();time_init();sched_clock_init();profile_init();if (!irqs_disabled())printk(KERN_CRIT "start_kernel(): bug: interrupts were " "enabled early\n");early_boot_irqs_on();local_irq_enable();/** HACK ALERT! This is early. We're enabling the console before* we've done PCI setups etc, and console_init() must beaware of* this. But we do want output early, in case something goes wrong.*/console_init();if (panic_later)panic(panic_later, panic_param);lockdep_info();/** Need to run this when irqs are enabled, because it wants* to self-test [hard/soft]-irqs on/off lock inversion bugs* too:*/locking_selftest();#ifdef CONFIG_BLK_DEV_INITRDif (initrd_start && !initrd_below_start_ok &&page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - ""disabling it.\n",page_to_pfn(virt_to_page((void *)initrd_start)),min_low_pfn);initrd_start = 0;}#endifvmalloc_init();vfs_caches_init_early(); cpuset_init_early();page_cgroup_init();mem_init();enable_debug_pagealloc(); cpu_hotplug_init();kmem_cache_init(); debug_objects_mem_init(); idr_init_cache();setup_per_cpu_pageset(); numa_policy_init();if (late_time_init)late_time_init();calibrate_delay();pidmap_init();pgtable_cache_init();prio_tree_init();anon_vma_init();#ifdef CONFIG_X86if (efi_enabled)efi_enter_virtual_mode();#endifthread_info_cache_init();cred_init();fork_init(num_physpages);proc_caches_init();buffer_init();key_init();security_init();vfs_caches_init(num_physpages);radix_tree_init();signals_init();/* rootfs populating might need page-writeback */ page_writeback_init();#ifdef CONFIG_PROC_FSproc_root_init();#endifcgroup_init();cpuset_init();taskstats_init_early();delayacct_init();check_bugs();acpi_early_init(); /* before LAPIC and SMP init */ftrace_init();/* Do the rest non-__init'ed, we're now alive */rest_init();}tatic noinline void __init_refok rest_init(void)__releases(kernel_lock){int pid;kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);numa_default_policy();pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); unlock_kernel();/** The boot idle thread must execute schedule()* at least once to get things moving:*/init_idle_bootup_task(current);rcu_scheduler_starting();preempt_enable_no_resched();schedule();preempt_disable();/* Call into cpu_idle with preempt disabled */cpu_idle();}static noinline int init_post(void){/* need to finish all async __init code before freeing the memory */async_synchronize_full();free_initmem();unlock_kernel();mark_rodata_ro();system_state = SYSTEM_RUNNING;numa_default_policy();if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)printk(KERN_WARNING "Warning: unable to open aninitial console.\n");(void) sys_dup(0);(void) sys_dup(0);current->signal->flags |= SIGNAL_UNKILLABLE;if (ramdisk_execute_command) {run_init_process(ramdisk_execute_command);printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command);}/** We try each of these until one succeeds.** The Bourne shell can be used instead of init if we are* trying to recover a really broken machine.*/if (execute_command) {run_init_process(execute_command);printk(KERN_WARNING "Failed to execute %s. Attempting ""defaults...\n", execute_command);}run_init_process("/sbin/init"); 根文献系统下令run_init_process("/etc/init");run_init_process("/bin/init");run_init_process("/bin/sh");panic("No init found. Try passing init= option to kernel."); }。
linux内核部件分析(九)——设备驱动模型之device
linux内核部件分析(九)——设备驱动模型之device前面我们分析了device、driver、bus三种类型,主要是三者的注册与注销,在sysfs中的目录与属性文件创建等内容。
本节就来详细分析下,在设备注册到总线上时,总线是如何为其寻找对应的驱动的;在驱动注册到总线上时,总线又是如何为其寻找对应的设备的。
本节的实现代码集中在drivers/base/bus.c和drivers/base/dd.c中。
先来回忆下,在device_register()->device_add()中,先是调用bus_add_device()添加device与bus间的联系,并添加bus 为device定义的属性,然后会调用bus_probe_device()。
bus_probe_device()会试图为已挂在总线上的该设备寻找对应的驱动。
我们的故事就从这里开始。
[cpp] view plaincopyprint?/** * bus_probe_device - probe drivers for a new device * @dev: device to probe * * - Automatically probe for a driver if the bus allows it. */ void bus_probe_device(struct device *dev) { struct bus_type *bus = dev->bus; int ret; if (bus&& bus->p->drivers_autoprobe){ ret = device_attach(dev);WARN_ON(ret < 0); } } bus_probe_device()为总线上的设备寻找驱动。
它先是检查bus->p->drivers_autoprobe,看是否允许自动探测。
Linux Device Model
struct kobject
struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset; struct kobj_type *ktype; struct sysfs_dirent *sd; struct kref kref; unsigned int state_initialized:1; unsigned int state_in_sysfs:1; unsigned int state_add_uevent_sent:1; unsigned int state_remove_uevent_sent:1; unsigned int uevent_suppress:1; };
struct kobj_type { void (*release)(struct kobject *); const struct sysfs_ops sysfs_ops; struct attribute **default_attrs; };
ktypes
• Describes default behavior for a family of kobjects
sysfs
• In-memory virtual file system • Provides view of the kobject hierarchy • Enables users to view device topology of system • kobjects can export files that enable kernel variables to be read and written
Linux Device Model 2
• Probe method:
int (*probe)(struct device *dev);
• Called when new device or driver added to bus • Callback the specific driver’s probe to initialize matched device
struct kset_uevent_ops { int (*filter)(struct kset *kset, struct kobject *kobj); char *(*name)(struct kset *kset, struct kobject *kobj); int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp, struct kobj_uevent_env *env); }
• E.g., “all block devices”
Kernel Events Layer
• Implements kernel-to-user notification system on top of kobjects
• Otherwise known as hotplug event • E.g., Hard drive full! Hard drive destruction pending!
• Ktype – Describes default behavior for a family of kobjects
• Enables kernel objects to share common operations
• Kset – Collection of related kobjects into same place
Linux2.6内核设备模型分析
挂接的总线类 型组织成层 次结构 ; B s目录 : u 包含 系统 中所有的总线类 型; D i r 目录 : r es v 包括 内核中所有 已注册 的设 备驱动
程序 ;
Cas目录 : l s 系统 中的设 备类型 ( 如网卡设备 , 卡 声 设 备等) 。
kb e 是 Ln X2 6引入 的新 的设 备 管理 机 制 , oj t ;u . e 在 内核 中 由 s utkb c 表示[ 3 ] t c oj t r e 1 。通 过这 个 数据 ,4 结构使所 有设备 在底层都 具有统 一 的接 口,oj t kb c 提 e 供 基本 的对象 管理 , 是构成 Ln x , iu 6设备模 型的核心 2 结 构 , 与 ss 文件 系统紧 密关联 , 它 yf s 每个 在 内核中注
LIZ e g pn XU a C N u — ig DAIGu n —h n h n — ig, Ch o, HE J nn n , a gz e
( col f l t nc c ne& T cn l y A hi ie i ,H f 30 9 C i ) Sh o o e r iS i c E co e eh o g , n u Unvr t o s y ee2 0 3 , hn i a
了全新 的设备模型。文中在 Lnx2 x . i 2 6内核设备模型 的架构和基 u 本原理 , 为深 入理解 2 6内核 的设备 管理 和驱动程 序 .
开发提供必要 的基础。
2 内核对象机制关键数据结构
2 1 k bet . oje 内核 对象
Ab ta tLiu 6k r e to u e nf dd vc rv rmo e ,whc at u p r tlg n we nge n ,h t lga dp p src : n x2. e ln rd c sau ie e ied ie d l n i i ihcrs p o tn el e tp i i o rma a me t o —pu n n
linux内核2.6
越来越多的Linuxer开始对尚处在测试中的2.6内核产生了兴趣,确实它非常具有吸引力,众多的特性让人眼花潦乱。
我也从2.4全面转到了2.6内核之下,享受着新特性带来的新鲜体验。
不过不少兄弟在编译新内核时或多或少的遇到了一些问题,看来新娘的盖头也不是那么容易揭开的:)因此我打算写一些文章来介绍编译新内核时的一些应该注意的地方,以减少兄弟们在编译新内核时的麻烦。
由于我的水平十分有限,写这样的文章实在是勉为其难。
文中肯定有错误疏失之处,还请兄弟们多多包涵:)第一部分,准备:要使用新的内核首先当然要取得新内核的源码,内核的官方网站是 在上面可以得到最新的内核。
2.6的更新是相当快的,你可以在命令行下使用finger @命令来快速得到当前最新的内核列表。
在这篇文章中我将以2.6.0-test6为准。
下载了内核源码之后,我们要使用tar jxvf linux-2.6.0-test6.tar.bz2来提取源码,如果你下载的是以tgz结尾的压缩包就使用zxvf参数来解压。
我强烈建议你不要使用/usr/src/linux这个目录来存放源码,因为使用这个目录你需要手工在/usr/include目录下作一些符号链接,这实在不是一个好主意。
所以我建议你为源码单独建一个目录,这里我们的目录是/src/linux-2.6.0-test6。
要编译与正常运行新的内核你需要升级一些软件包,这些信息在源码目录下的Documentation/Changes 文件中,请根据你的实际情况选择升级。
这其中我强调一下你应该升级Module-Init-Tools,不要被你当前系统中depmod -V输出的版本号迷惑(在RH9中它的输出是2.4.22,感觉好象要比Changes中所要求的要高,实际上它们使用不同的版本规则)。
新的Module-Init-Tools在下面的网址中取得:/pub/linux/kernel/people/rusty/modules/我使用的是0.9.14。
Linux2.6内核配置详解
7.
[*] Automatic kernel module loading
复制代码
Enable loadable module support,很多人喜欢将全部功能、硬件支持一股脑的编 进内核,而不是使用模块的方式。这样做非常不好(个
人觉得)。其实我也做过嵌入式的开发,在针 对特定硬件的平台下尽可能将内核编小,将始终是支持 模块加载的。例如我们开发的防火墙就是做为内核的模 块被加载的。使用模块支持,你的系统能具有更好的可 扩充性。还有一个原因就是自己编写的功能模块、设备 驱动模块(假设编写的质量不高)以模块方式工作引起
2.
[*] Enable loadable module support
3.
[*] Module unloading
4.
[]
Forced module unloading
5.
[*] Module versioning support
(EXPERIMENTAL)
6.
[ ] Source checksum for all modules
Support for hot-pluggable devices:是否支持热插拔 的选项,肯定要选上。不然 USB、PCMCIA 等这些设备都
用不了。
Kernel Userspace Events:内核中分为系统区和用户区, 这里系统区和用户区进行通讯的一种方式,选上。
Kernel .config support:将.config 配置信息保存在 内核中,选上它及它的子项使得其它用户能从/proc 中 得到内核的配置。还记得另一篇贴子我是如何取得启动 光盘的内核配置信息,并在此基础上配置新的内核吗?
microcode support
14_LinuxDeviceModel
Object lifecycles
Reference count
Device model tree
Sysfs (跑個tree /sys 吧?)
/proc, /dev, /sysfs
Authors can ignore the model, and trust it Understanding device model is good, if struct leaks
Reference count
struct kobject *kobject_get(struct kobject *kobj); //++ void kobject_put(struct kobject *kobj); //--, 0 to cleanup “struct module *owner” in struct cdev?
$(KERNELDIR)/lib/kobject*.c
Kobject basics (0/3)
1. struct kobject { 2. const char * k_name; 3. char name[KOBJ_NAME_LEN]; 4. struct kref kref; 5. struct list_head entry; 6. struct kobject * parent; 7. struct kset * kset; 8. struct kobj_type * ktype; 9. struct dentry * dentry; 10. }; 11. struct kset { 12. struct subsystem * subsys; 13. struct kobj_type * ktype; 14. struct list_head list; 15. spinlock_t list_lock; 16. struct kobject kobj; 17. struct kset_hotplug_ops * hotplug_ops; 18. };
Linux-2.6内核编译配置选项简介
Linux-2.6内核编译配置选项简介code maturity level options代码成熟度选项prompt for development and/or incomplete code/drivers显示尚在开发中或尚未完成的代码与驱动.除非你是测试人员或者开发者,否则请勿选择general setup常规设置local version - append to kernel release在内核版本后面加上自定义的版本字符串(小于64字符),可以用"uname -a"命令看到automatically append version information to the version string自动在版本字符串后面添加版本信息,编译时需要有perl以及git仓库支持support for paging of anonymous memory (swap)使用交换分区或者交换文件来做为虚拟内存system v ipcsystem v进程间通信(ipc)支持,许多程序需要这个功能.必选,除非你知道自己在做什么ipc namespacesipc命名空间支持,不确定可以不选posix message queuesposix消息队列,这是posix ipc中的一部分bsd process accounting将进程的统计信息写入文件的用户级系统调用,主要包括进程的创建时间/创建者/内存占用等信息bsd process accounting version 3 file format使用新的第三版文件格式,可以包含每个进程的pid和其父进程的pid,但是不兼容老版本的文件格式export task/process statistics through netlink通过netlink接口向用户空间导出任务/进程的统计信息,与bsd process accounting的不同之处在于这些统计信息在整个任务/进程生存期都是可用的enable per-task delay accounting在统计信息中包含进程等候系统资源(cpu,io同步,内存交换等)所花费的时间uts namespacesuts名字空间支持,不确定可以不选auditing support审计支持,某些内核模块(例如selinux)需要它,只有同时选择其子项才能对系统调用进行审计enable system-call auditing support支持对系统调用的审计kernel .config support把内核的配置信息编译进内核中,以后可以通过scripts/extract-ikconfig脚本来提取这些信息enable access to .config through /proc/config.gz允许通过/proc/config.gz访问内核的配置信息cpuset support只有含有大量cpu(大于16个)的smp系统或numa(非一致内存访问)系统才需要它kernel->user space relay support (formerly relayfs)在某些文件系统上(比如debugfs)提供从内核空间向用户空间传递大量数据的接口initramfs source file(s)initrd已经被initramfs取代,如果你不明白这是什么意思,请保持空白optimize for size (look out for broken compilers!)编译时优化内核尺寸(使用"-os"而不是"-o2"参数编译),有时会产生错误的二进制代码enable extended accounting over taskstats收集额外的进程统计信息并通过taskstats接口发送到用户空间configure standard kernel features (for small systems)配置标准的内核特性(为小型系统)enable 16-bit uid system calls允许对uid系统调用进行过时的16-bit包装sysctl syscall support不需要重启就能修改内核的某些参数和变量,如果你也选择了支持/proc,将能从/proc/sys 存取可以影响内核行为的参数或变量load all symbols for debugging/kksymoops装载所有的调试符号表信息,仅供调试时选择include all symbols in kallsyms在kallsyms中包含内核知道的所有符号,内核将会增大300kdo an extra kallsyms pass除非你在kallsyms中发现了bug并需要报告这个bug才打开该选项support for hot-pluggable devices支持热插拔设备,如usb与pc卡等,udev也需要它enable support for printk允许内核向终端打印字符信息,在需要诊断内核为什么不能运行时选择bug() support显示故障和失败条件(bug和warn),禁用它将可能导致隐含的错误被忽略enable elf core dumps内存转储支持,可以帮助调试elf格式的程序enable full-sized data structures for core在内核中使用全尺寸的数据结构.禁用它将使得某些内核的数据结构减小以节约内存,但是将会降低性能enable futex support快速用户空间互斥体可以使线程串行化以避免竞态条件,也提高了响应速度.禁用它将导致内核不能正确的运行基于glibc的程序enable eventpoll support支持事件轮循的系统调用use full shmem filesystem完全使用shmem来代替ramfs.shmem是基于共享内存的文件系统(可能用到swap),在启用tmpfs后可以挂载为tmpfs供用户空间使用,它比简单的ramfs先进许多use full slab allocator使用slab完全取代slob进行内存分配,slab是一种优秀的内存分配管理器,推荐使用enable vm event counters for /proc/vmstat允许在/proc/vmstat中包含虚拟内存事件记数器loadable module support可加载模块支持enable loadable module support打开可加载模块支持,如果打开它则必须通过"make modules_install"把内核模块安装在/lib/modules/中module unloading允许卸载已经加载的模块forced module unloading允许强制卸载正在使用中的模块(比较危险)module versioning support允许使用其他内核版本的模块(可能会出问题)source checksum for all modules为所有的模块校验源码,如果你不是自己编写内核模块就不需要它automatic kernel module loading让内核通过运行modprobe来自动加载所需要的模块,比如可以自动解决模块的依赖关系block layer块设备层enable the block layer块设备支持,使用硬盘/usb/scsi设备者必选support for large block devices仅在使用大于2tb的块设备时需要support for tracing block io actions块队列io跟踪支持,它允许用户查看在一个块设备队列上发生的所有事件,可以通过blktrace程序获得磁盘当前的详细统计数据support for large single files仅在可能使用大于2tb的文件时需要io schedulersio调度器anticipatory i/o scheduler假设一个块设备只有一个物理查找磁头(例如一个单独的sata硬盘),将多个随机的小写入流合并成一个大写入流,用写入延时换取最大的写入吞吐量.适用于大多数环境,特别是写入较多的环境(比如文件服务器)deadline i/o scheduler使用轮询的调度器,简洁小巧,提供了最小的读取延迟和尚佳的吞吐量,特别适合于读取较多的环境(比如数据库)cfq i/o scheduler使用qos策略为所有任务分配等量的带宽,避免进程被饿死并实现了较低的延迟,可以认为是上述两种调度器的折中.适用于有大量进程的多用户系统default i/o scheduler默认io调度器processor type and features中央处理器(cpu)类型及特性symmetric multi-processing support对称多处理器支持,如果你有多个cpu或者使用的是多核cpu就选上.此时"enhanced real time clock support"选项必须开启,"advanced power management"选项必须关闭subarchitecture type处理器的子架构,大多数人都应当选择"pc-compatible"processor family处理器系列,请按照你实际使用的cpu选择generic x86 support通用x86支持,如果你的cpu能够在上述"processor family"中找到就别选hpet timer supporthpet是替代8254芯片的新一代定时器,i686及以上级别的主板都支持,可以安全的选上maximum number of cpus支持的最大cpu数,每增加一个内核将增加8k体积smt (hyperthreading) scheduler support支持intel的超线程(ht)技术multi-core scheduler support针对多核cpu进行调度策略优化preemption model内核抢占模式no forced preemption (server)适合服务器环境的禁止内核抢占voluntary kernel preemption (desktop)适合普通桌面环境的自愿内核抢占preemptible kernel (low-latency desktop)适合运行实时程序的主动内核抢占preempt the big kernel lock可以抢占大内核锁,应用于实时要求高的场合,不适合服务器环境machine check exception让cpu检测到系统故障时通知内核,以便内核采取相应的措施(如过热关机等)check for non-fatal errors on amd athlon/duron / intel pentium 4每5秒检测一次这些cpu的非致命错误并纠正它们,同时记入日志check for p4 thermal throttling interrupt当p4的cpu过热时显示一条警告消息enable vm86 support虚拟x86支持,在dosemu下运行16-bit程序或xfree86通过bios初始化某些显卡的时候才需要toshiba laptop supporttoshiba笔记本模块支持dell laptop supportdell笔记本模块支持enable x86 board specific fixups for reboot修正某些旧x86主板的重起bug,这种主板基本绝种了/dev/cpu/microcode - intel ia32 cpu microcode support使用不随linux内核发行的ia32微代码,你必需有ia32微代码二进制文件,仅对intel的cpu 有效/dev/cpu/*/msr - model-specific register support在多cpu系统中让特权cpu访问x86的msr寄存器/dev/cpu/*/cpuid - cpu information support能从/dev/cpu/x/cpuid获得cpu的唯一标识符(cpuid)firmware drivers固件驱动程序bios enhanced disk drive calls determine boot disk有些bios支持从某块特定的硬盘启动(如果bios不支持则可能无法启动),目前大多数bios 还不支持bios update support for dell systems via sysfs仅适用于dell机器dell systems management base driver仅适用于dell机器high memory support最高内存支持,总内存小于等于1g的选"off",大于4g的选"64g"memory split如果你不是绝对清楚自己在做什么,不要改动这个选项memory model一般选"flat memory",其他选项涉及内存热插拔64 bit memory and io resources使用64位的内存和io资源allocate 3rd-level pagetables from highmem在内存很多(大于4g)的机器上将用户空间的页表放到高位内存区,以节约宝贵的低端内存math emulation数学协处理器仿真,486dx以上的cpu就不要选它了mtrr (memory type range register) support打开它可以提升pci/agp总线上的显卡2倍以上的速度,并且可以修正某些bios错误boot from efi supportefi是一种可代替传统bios的技术(目前的grub/lilo尚不能识别它),但是现在远未普及enable kernel irq balancing让内核将irq中断平均分配给多个cpu以进行负载均衡,但是要配合irqbanlance守护进程才行use register arguments使用"-mregparm=3"参数编译内核,将前3个参数以寄存器方式进行参数调用,可以生成更紧凑和高效的代码enable seccomp to safely compute untrusted bytecode只有嵌入式系统可以不选timer frequency内核时钟频率,桌面推荐"1000 hz",服务器推荐"100 hz"或"250 hz"kexec system call提供kexec系统调用,可以不必重启而切换到另一个内核kernel crash dumps被kexec启动后产生内核崩溃转储physical address where the kernel is loaded内核加载的物理地址,除非你知道自己在做什么,否则不要修改.在提供kexec系统调用的情况下可能要修改它support for hot-pluggable cpus对热插拔cpu提供支持compat vdso support如果glibc版本大于等于2.3.3就不选,否则就选上power management options电源管理选项power management support电源管理有apm和acpi两种标准且不能同时使用.即使关闭该选项,x86上运行的linux也会在空闲时发出hlt指令将cpu进入睡眠状态legacy power management api传统的电源管理api,比如软关机和系统休眠等接口power management debug support仅供调试使用driver model /sys/devices/.../power/state files内核帮助文档反对使用该选项,即将被废除acpi (advanced configuration and power interface) support必须运行acpid守护程序acpi才能起作用.acpi是为了取代apm而设计的,因此应该尽量使用acpi而不是apmac adapter如果你的系统可以在ac和电池之间转换就可以选battery通过/proc/acpi/battery向用户提供电池状态信息,用电池的笔记本可以选button守护程序捕获power,sleep,lid按钮事件,并根据/proc/acpi/event做相应的动作,软件控制的poweroff需要它video仅对集成在主板上的显卡提供acpi2.0支持,且不是所有集成显卡都支持generic hotkey统一的热键驱动,建议不选fan允许通过用户层的程序来对系统风扇进行控制(开,关,查询状态),支持它的硬件并不多dock支持由acpi控制的集线器(docking stations)processor让acpi处理空闲状态,并使用acpi c2和c3处理器状态在空闲时节省电能,同时它还被cpufreq的"performance-state drivers"选项所依赖thermal zone系统温度过高时可以利用acpi thermal zone及时调整工作状态以避免你的cpu被烧毁asus/medion laptop extrasasus笔记本专用,以提供额外按钮的支持,用户可以通过/proc/acpi/asus来打开或者关闭lcd的背光/调整亮度/定制led的闪烁指示等功能ibm thinkpad laptop extrasibm thinkpad专用toshiba laptop extrastoshiba笔记本专用disable acpi for systems before jan 1st this year输入四位数的年份,在该年的1月1日前不使用acpi的功能("0"表示一直使用)debug statements详细的acpi调试信息,不搞开发就别选power management timer support这个timer在所有acpi兼容的平台上都可用,且不会受pm功能的影响,建议总是启用它.如果你在kernel log中看到了'many lost ticks'那就必须启用它acpi0004,pnp0a05 and pnp0a06 container driver支持内存和cpu的热插拔smart battery system支持依赖于i2c的"智能电池".这种电池非常老旧且罕见,还与当前的acpi标准兼容性差apm (advanced power management) bios supportapm在smp机器上必须关闭,一般来说当前的笔记本都支持acpi,所以应尽量关闭该该选项ignore user suspend只有nec versa m系列的笔记本才需要选择这一项enable pm at boot time系统启动时即启用apm,选上这个选项能让系统自动的进行电源管理,但常常导致启动时死机make cpu idle calls when idle系统空闲时调用空闲指令(halt),只有老式的cpu才需要选它,且对于smp系统必须关闭enable console blanking using apm在屏幕空白时关闭lcd背光,事实上对所有的笔记本都无效rtc stores time in gmt将硬件时钟应该设为格林威治时间,否则视为本地时间.建议你使用gmt,这样你无须为时区的改变而担心allow interrupts during apm bios calls允许apm的bios调用时中断,ibm thinkpad的一些新机器需要这项.如果休眠时挂机(包括睡下去就醒不来),可以试试它use real mode apm bios call to power off此驱动为某些有bug的bios准备,如果你的系统不能正常关机或关机时崩溃,可以试试它cpu frequency scaling允许动态改变cpu主频,达到省电和降温的目的,必须同时启用下面的一种governor才行enable cpufreq debugging允许对cpufreq进行调试cpu frequency translation statistics通过sysfs文件系统输出cpu频率变换的统计信息cpu frequency translation statistics details输出详细的cpu频率变换统计信息default cpufreq governor默认的cpu频率调节器'performance' governor'性能'优先,静态的将频率设置为cpu支持的最高频率'powersave' governor'节能'优先,静态的将频率设置为cpu支持的最低频率'userspace' governor for userspace frequency scaling既允许手动调整cpu频率,也允许用户空间的程序动态的调整cpu频率(需要额外的调频软件,比如cpufreqd)'ondemand' cpufreq policy governor'立即响应',周期性的考察cpu负载并自动的动态调整cpu频率(不需要额外的调频软件),适合台式机'conservative' cpufreq governor'保守',和'ondemand'相似,但是频率的升降是渐变式的(幅度不会很大),更适合用于笔记本/pda/amd64环境acpi processor p-states driver将acpi2.0的处理器性能状态报告给cpufreq processor drivers以决定如何调整频率,该选项依赖于acpi->processor{省略的部分请按照自己实际使用的cpu选择}/proc/acpi/processor/../performance interface内核帮助文档反对使用该选项,即将被废除relaxed speedstep capability checks放松对系统的speedstep兼容性检查,仅在某些老旧的intel系统上需要打开bus options (pci, pcmcia, eisa, mca, isa)总线选项pci supportpci支持,如果使用了pci或pci express设备就必选pci access modepci访问模式,强列建议选"any"(系统将优先使用"mmconfig",然后使用"bios",最后使用"direct"检测pci设备)pci express supportpci express支持(目前主要用于显卡和千兆网卡)pci express hotplug driver如果你的主板和设备都支持pci express热插拔就可以选上use polling mechanism for hot-plug events对热插拔事件采用轮询机制,仅用于测试目的root port advanced error reporting support由pci express aer驱动程序处理发送到root port的错误信息message signaled interrupts (msi and msi-x)pci express支持两类中断:intx使用传统的irq中断,可以与现行的pci总线的驱动程序和操作系统兼容;msi则是通过inbound memory write触发和发送中断,更适合多cpu系统.可以使用"pci=nomsi"内核引导参数关闭msipci debugging将pci调试信息输出到系统日志里interrupts on hypertransport devices允许本地的hypertransport设备使用中断isa support现在基本上没有isa的设备了,如果你有就选吧mca support微通道总线,老旧的ibm的台式机和笔记本上可能会有这种总线natsemi scx200 support在使用amd geode处理器的机器上才可能有pccard (pcmcia/cardbus) supportpcmcia卡(主要用于笔记本)支持enable pccard debugging仅供调试16-bit pcmcia support一些老的pcmcia卡使用16位的cardbus32-bit cardbus support当前的pcmcia卡基本上都是32位的cardbuscardbus yenta-compatible bridge support使用pcmcia卡的基本上都需要选择这一项,子项请按照自己实际使用的pcmcia卡选择{省略的部分请按照自己实际使用的pcmcia卡选择}pci hotplug supportpci热插拔支持,如果你有这样的设备就到子项中去选吧executable file formats可执行文件格式kernel support for elf binarieself是开放平台下最常用的二进制文件格式,支持动态连接,支持不同的硬件平台.除非你知道自己在做什么,否则必选kernel support for a.out and ecoff binaries早期unix系统的可执行文件格式,目前已经被elf格式取代kernel support for misc binaries允许插入二进制的封装层到内核中,使用java,.net,python,lisp等语言编写的程序时需要它networking网络networking options网络选项network packet debugging在调试不合格的包时加上额外的附加信息,但在遇到dos攻击时你可能会被日志淹没packet socket这种socket可以让应用程序(比如tcpdump,iptables)直接与网络设备通讯,而不通过内核中的其它中介协议packet socket: mmapped io让packet socket驱动程序使用io映射机制以使连接速度更快unix domain sockets一种仅运行于本机上的效率高于tcp/ip的socket,简称unix socket.许多程序都使用它在操作系统内部进行进程间通信(ipc),比如x window和syslogtransformation user configuration interface为ipsec(可在ip层加密)之类的工具提供xfrm用户配置接口支持transformation sub policy supportxfrm子策略支持,仅供开发者使用pf_key sockets用于可信任的密钥管理程序和操作系统内核内部的密钥管理进行通信,ipsec依赖于它tcp/ip networkingtcp/ip协议当然要选ip: multicasting群组广播,似乎与网格计算有关,仅在使用mbone的时候才需要ip: advanced router高级路由,如果想做一个路由器就选吧ip: policy routing策略路由ip: equal cost multipath用于路由的基于目的地址的负载均衡ip: verbose route monitoring显示冗余的路由监控信息ip: kernel level autoconfiguration在内核启动时自动配置ip地址/路由表等,需要从网络启动的无盘工作站才需要这个东西ip: tunnelingip隧道,将一个ip报文封装在另一个ip报文内的技术ip: gre tunnels over ip基于ip的gre(通用路由封装)隧道ip: multicast routing多重传播路由ip: arp daemon support这东西尚处于试验阶段就已经被废弃了ip: tcp syncookie support抵抗syn flood攻击的好东西,要启用它必须同时启用/proc文件系统和"sysctl support",然后在系统启动并挂载了/proc之后执行"echo 1 >/proc/sys/net/ipv4/tcp_syncookies"命令ip: ah transformationipsec验证头(ah)实现了数据发送方的验证处理,可确保数据既对于未经验证的站点不可用也不能在路由过程中更改ip: esp transformationipsec封闭安全负载(esp)实现了发送方的验证处理和数据加密处理,用以确保数据不会被拦截/查看或复制ip: ipcomp transformationipcomp(ip静荷载压缩协议),用于支持ipsecip: ipsec transport modeipsec传输模式,常用于对等通信,用以提供内网安全.数据包经过了加密但ip头没有加密,因此任何标准设备或软件都可查看和使用ip头ip: ipsec tunnel modeipsec隧道模式,用于提供外网安全(包括虚拟专用网络).整个数据包(数据头和负载)都已经过加密处理且分配有新的esp头/ip头和验证尾,从而能够隐藏受保护站点的拓扑结构ip: ipsec beet modeipsec beet模式inet: socket monitoring interfacesocket监视接口,一些linux本地工具(如:包含ss的iproute2)需要使用它tcp: advanced congestion control高级拥塞控制,如果没有特殊需求(比如无线网络)就别选了,内核会自动将默认的拥塞控制设为"cubic"并将"reno"作为候补ip: virtual server configurationip虚拟服务器允许你基于多台物理机器构建一台高性能的虚拟服务器,不玩集群就别选了the ipv6 protocol你要是需要ipv6就选吧netlabel subsystem supportnetlabel子系统为诸如cipso与ripso之类能够在分组信息上添加标签的协议提供支持,如果你看不懂就别选了security marking对网络包进行安全标记,类似于nfmark,但主要是为安全目的而设计,如果你不明白的话就别选。
Linux在无线传感器Imote2上的移植与应用
V 13 o . 6
No 4 .
计
算
机
工
程
21 0 0年 2月
Fe u y 2 0 br ar 01
Co put rEngi e i m e ne rng
・ 开发研究与设计技术 ・
文 编 1 3 8 o ) ’21 文 标 码: 章 号: 0 _ 4 ( 1o _ 9 3 0 2 2 o 0 — 献 识 A
通常包含传感器、数据处理、通信 和电源 4个模块 ,分别 完 成数据的采集 、处理、传输 功能 以及供 电功能川。图 1所示
为 传 感器 节 点 的组 成 。
处 器模 块
2 嵌 入 式 Ln x的优势 iu
Tn O iy S是美 国加州大学伯克利分校专为 WS N开发的基 于构件 、事件驱动 的轻量级操作系统 ,其设计的主 要 目标是 支持低功 耗、小代码量、高并发操作和高效通信。下面分别 从任务调度、运行空间、实 时性和代码的可移植性 4个 方面 对两者进行 比较 。 () 1在任务调度方面 ,Tn O iy S采 用简单的 FF IO任 务调度 和事件驱动策略 ,比较适合 WS 的低功耗、高并发性 的特 N
CUIW e, HIDi n x , NG , i S a - i DI Bo RAo a g Xi n
( c o l f o ue , t n l iest o e e s e h oo y C a g h 1 0 3 S h o o mp trNai a Unv ri f fn eT c n lg , h n s a 0 7 ) C o y D 4
中 分 号 N4 国 类 : 9 5
L n x在 无 线传 感 器 I t2上 的移 植 与应 用 iu moe
Linux内核驱动:cdev、misc以及device三者之间的联系和区别
Linux内核驱动:cdev、misc以及device三者之间的联系和区别Linux内核驱动:cdev、misc以及device三者之间的联系和区别背景我想在cdev中使⽤dev_err等log打印函数,但是跟踪了⼀下cdev中的原型,发现并不是我想要的。
常见的驱动是这样⼦使⽤dev_err的:// 某个驱动,这⾥是电池有关的static int32_t oz8806_read_byte(struct oz8806_data *data, uint8_t index, uint8_t *dat){struct i2c_client *client = data->myclient;// ...dev_err(&client->dev, "%s: err %d, %d times\n", __func__, ret, i);// ...}⽽i2c_client原型是这样⼦的,dev就是⼀个device:// include/linux/i2c.hstruct i2c_client {// ...struct device dev; /* the device structure */// ...};那么,我想只要找到cdev中的dev,也可以这样⼦⽤,对吧?但是:// include/linux/cdev.hstruct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;} __randomize_layout;⽽dev_t长这个样⼦:// include/linux/types.htypedef u32 __kernel_dev_t;typedef __kernel_dev_t dev_t;我在困惑dev_t是什么东西以后,找到了下⾯这篇⽂章。
Linux 2.6内核的设备模型
Linux 2.6内核的设备模型Linux 2.6内核的设备模型Linux 2.6内核的一个重要特色是提供了统一的内核设备模型。
随着技术的不断进步,系统的拓扑结构越来越复杂,对智能电源管理、热插拔以及plug and play的支持要求也越来越高,2.4内核已经难以满足这些需求。
为适应这种形势的需要,2.6内核开发了全新的设备模型。
1.Sysfs文件系统Sysfs文件系统是一个类似于proc文件系统的特殊文件系统,用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息。
其顶层目录主要有:Block目录:包含所有的块设备Devices目录:包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构Bus目录:包含系统中所有的总线类型Drivers目录:包括内核中所有已注册的设备驱动程序Class目录:系统中的设备类型(如网卡设备,声卡设备等)2.内核对象机制关键数据结构2.1 kobject内核对象Kobject是Linux 2.6引入的新的设备管理机制,在内核中由struct kobject表示。
通过这个数据结构使所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux 2.6设备模型的核心结构,它与sysfs文件系统紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。
Kobject结构定义为:struct kobject {char * k_name; 指向设备名称的指针char name[KOBJ_NAME_LEN]; 设备名称struct kref kref; 对象引用计数struct list_head entry; 挂接到所在kset中去的单元struct kobject * parent; 指向父对象的指针struct kset * kset; 所属kset的指针struct kobj_type * ktype; 指向其对象类型描述符的指针struct dentry * dentry; sysfs文件系统中与该对象对应的文件节点路径指针};其中的kref域表示该对象引用的计数,内核通过kref实现对象引用计数管理,内核提供两个函数kobject_get()、kobject_put()分别用于增加和减少引用计数,当引用计数为0时,所有该对象使用的资源将被释放。
linux设备驱动(2)device详解
linux设备驱动(2)device详解Linux设备驱动的模型,是建⽴在sysfs设备⽂件系统和kobject上的,由总线(bus)、设备(device)、驱动(driver)和类(class)所组成的关系结构,在底层,Linux系统中的每个设备都有⼀个device结构体的实例。
struct device已在上⼀博⽂中介绍,下⾯按顺序详细介绍device的主要API。
1.device_createsource位于:drivers\base\Core.c。
向sysfs注册⼀个device,提供了强⼤的格式化注册接⼝。
1/**2 * device_create - creates a device and registers it with sysfs3 * @class: pointer to the struct class that this device should be registered to4 * @parent: pointer to the parent struct device of this new device, if any5 * @devt: the dev_t for the char device to be added6 * @drvdata: the data to be added to the device for callbacks7 * @fmt: string for the device's name8 *9 * This function can be used by char device classes. A struct device10 * will be created in sysfs, registered to the specified class.11 *12 * A "dev" file will be created, showing the dev_t for the device, if13 * the dev_t is not 0,0.14 * If a pointer to a parent struct device is passed in, the newly created15 * struct device will be a child of that device in sysfs.16 * The pointer to the struct device will be returned from the call.17 * Any further sysfs files that might be required can be created using this18 * pointer.19 *20 * Returns &struct device pointer on success, or ERR_PTR() on error.21 *22 * Note: the struct class passed to this function must have previously23 * been created with a call to class_create().24*/25struct device *device_create(struct class *class, struct device *parent,26 dev_t devt, void *drvdata, const char *fmt, ...)27 {28 va_list vargs;29struct device *dev;3031 va_start(vargs, fmt);32 dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);33 va_end(vargs);34return dev;35 }1.1device_create_vargs上⾯API只是为了提供完善的接⼝,下⾯API这个才是真正⼯作的。
Linux设备驱动编程模型之上层容器篇
分类:2012-10-06 17:18 245人阅读(0)2.6内核增加了一个引人注目的新特性——统一设备模型(device model)。
设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,从而使得系统具有以下优点:●∙∙∙∙∙∙∙∙代码重复最小化。
●∙∙∙∙∙∙∙∙提供诸如引用计数这样的统一机制。
●∙∙∙∙∙∙∙∙可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线。
●∙∙∙∙∙∙∙∙可以将系统中的全部设备结构以树的形式完整、有效的展现出来——包括所有的总线和内部连接。
●∙∙∙∙∙∙∙∙可以将设备和其对应的驱动联系起来,反之亦然。
●∙∙∙∙∙∙∙∙可以将设备按照类型加以归类,比如分类为输入设备,而无需理解物理设备的拓扑结构。
●∙∙∙∙∙∙∙∙可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确顺序关闭各设备的电源。
最后一点是实现设备模型的最初动机。
若想在内核中实现智能的电源管理,就需要来建立表示系统中设备拓扑关系的树结构。
当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以下的(处于叶子上的)设备电源。
比如内核需要先关闭一个USB鼠标,然后才可关闭USB控制器;同样内核也必须在关闭PCI总线前先关闭USB控制器。
简而言之,若要准确而又高效的完成上述电源管理目标,内核无疑需要一颗设备树。
一、原理虽然设备模型的初衷是为了方便电源管理而提供出的一种设备拓扑结构,但是,为了方便调试,设备模型的开发者决定将设备结构树导出为一个文件系统,这就是sysfs文件系统,它可以帮助用户能以一个简单文件系统的方式来观察系统中各种设备的拓扑结构。
这个举措很快被证明是非常明智的,首先sysfs代替了先前处于/proc下的设备相关文件;另外它为系统对象提供了一个很有效的视图。
实际上,sysfs起初被称为driverfs。
最终sysfs使得我们认识到一个全新的对象模型非常有利于系统。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux 2.6 Device Modelv1.2By semiyd2007/8/1semiyd@Linux2.6的设备模型是一个复杂的数据结构体系,不能用一种简单形象的结构来进行整体的描述。
本文试图用一些易于理解的方式,解释这个体系的构造。
总体上,会偏向与driver的相关内容,与driver不太相干的东东会相应的忽略,并且侧重对体系结构的理解,对device model中的很多技术细节就不去一一解释了,具体可以看《linux设备驱动程序》中的相关章节。
全文分为2大部分。
第一部分是解释整个体系结构。
第二部分是结合具体的驱动的内核注册过程,看一下体系的工作流程。
Part One: The Device Model在介绍这个体系之前,先要说明一下下列一些重要的概念。
KobjectKsetSubsystemSysfsBusDeviceClassDevice_driverKOBJECTkobject 是设备模型中的基本的结构。
从代码上看,是一个结构体。
但是linux中引入了面向对象的思想,从某些角度,也可以看成是一个类。
struct kobject {const char * k_name; //name of the kobjectcharname[KOBJ_NAME_LEN];counting(引用计数)//referencekrefstructkref;list_head entry;structstruct kobject * parent; //父类kset;*ksetstructstruct kobj_type * ktype;dentry;*structdentrypoll;wait_queue_head_t};kobject对象通常被嵌入到其他的结构中。
从面向对象的观点看,kobject可以看成是基类,而其他类都是派生的产物。
这一点在后面的图表中会有具体的说明。
不过这里还是举一个派生的例子:device_driver。
struct device_driver {*name;charconstbus_type *bus;structcompletion unloaded;structstruct kobject kobj;klist_devices;structklistklist_node knode_bus;structstruct module * owner;int (*probe) (struct device * dev);int (*remove) (struct device * dev);void (*shutdown) (struct device * dev);device * dev, pm_message_t state);(structint (*suspend)int (*resume) (struct device * dev);};各种操作:void kobject_init(struct kobject *); 初始化int kobject_add(struct kobject *); 加入kset并且在sysfs中显示kobject。
kobject不一定会在sysfs里显示,除非你调用了这个函数。
int kobject_register(struct kobject *); kobject_init和kobject_add的简单结合void kobject_del(struct kobject *);void kobject_unregister(struct kobject *);struct kobject * kobject_get(struct kobject *); 增加引用计数void kobject_put(struct kobject *); 减少引用计数kobject的一个重要函数是为他的结构设置引用计数(reference counting)。
只要对象的引用计数存在,对象(以及支持他的代码)就必须存在。
KSET一个kset是相同类型的kobject的一个集合。
这里所说的类型,是有一个叫kobj_type类型的指针来描述的。
kset一定会在sysfs里显示出来。
我们可以认为,他是kobject的顶层容器(container)类。
在每个kset的内部,包含了自己的kobject,并且可以用多种处理kobject的方法处理kset。
struct kset {struct subsystem * subsys;struct kobj_type * ktype;list_head list;structspinlock_t list_lock;kobj;kobjectstructstruct kset_uevent_ops * uevent_ops;};struct kobj_type {void (*release)(struct kobject *);struct sysfs_ops * sysfs_ops;struct attribute ** default_attrs;};不过这里的kset还不一定是顶部的,也就是说,在同属于相同的kobj_type类型下,他有可能是另外一个kset的一部分。
操作:void kset_init(struct kset * k);int kset_add(struct kset * k);int kset_register(struct kset * k);void kset_unregister(struct kset * k);static inline struct kset * kset_get(struct kset * k) //改动引用计数static inline void kset_put(struct kset * k) //改动引用计数SUBSYSTEM子系统通常就是整个体系的顶层结构。
在sysfs中,显示为/sys下面的第一级目录。
下面就来看看,通常/sys下面的目录结构:block/bus/class/devices/firmware/net/fs/这里,就可以看见诸如class(相当于struct class)之类的子系统。
struct subsystem {ksetkset;structstruct rw_semaphore rwsem; //用于串行访问kset内部的链表的信号量};在看刚刚的class例子struct class {*name;charconst*owner;modulestructstruct subsystem subsys;list_head children;structlist_head devices;structlist_head interfaces;structstruct semaphore sem; /* locks both the children and interfaces lists */struct class_attribute * class_attrs;struct class_device_attribute * class_dev_attrs;int (*uevent)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size);void (*release)(struct class_device *dev);void (*class_release)(struct class *class);};其实从定义上可以看出,子系统就是对一个kset和一个信号量的封装。
操作:extern void subsystem_init(struct subsystem *);extern int subsystem_register(struct subsystem *);extern void subsystem_unregister(struct subsystem *);但驱动程序的编写人员是不会用到subsys级别的初始化之类的调用的。
SYSFSsysfs是一种基于内存的文件结构。
简单的说,就是为内核的数据结构,一些属性,符号链接提供一个在用户空间中显示和交互的方式。
在系统里,显示为/sys文件夹。
mount -t sysfs /sys 就可以在文件系统里看见/sys的目录了。
每一个在kernel里面注册的kobject,在/sys里面都会产生一个相应的目录,名字就kobject的name。
那么如果这个kobject有父类的话,那它对应的目录就会成为父类的子目录,这样就可以反映kobject的继承关系。
下面是/sys下一级目录的结构。
block/bus/class/devices/firmware/net/fs/这里要提一个叫attribute的概念,也就是属性。
attribute是kobject里面的东西。
在sysfs中,属性能够以常规的文件的形式,输出到sysfs的目录当中。
并且,当kobject 的属性提供了读写的方法,sysfs中就可以对相应的文件进行读写,从而访问kobject里面的一些信息。
具体在kobject里面,有kobj_type结构:struct kobj_type {void (*release)(struct kobject *);struct sysfs_ops * sysfs_ops;struct attribute ** default_attrs;};struct attribute {*name;charconstowner;*modulestructmode_t mode;};attribute用于保存属性列表。
*name就是属性名了,也就是sysfs里面的文件名。
mode是保护位,如果是只读,就要设置成S_IRUGO,读写就是S_IWUSR。
struct sysfs_ops {ssize_t (*show)(struct kobject *, struct attribute *,char *); //读ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); //写};sysfs_ops就是具体怎么实现在用户空间/sys下面的读写操作了。
另外,如果希望在kobject的sysfs目录中添加新的属性,只需要填写一个attribute结构体,然后调用下面的函数:sysfs_create_file(struct kobject * kobj, const struct attribute * attr)如果把attribute看成一个基类的,那这里有一个衍生的类,叫device_attribute:struct device_attribute {struct attribute attr;ssize_t (*show)(struct device * dev, char * buf);ssize_t (*store)(struct device * dev, const char * buf);};相应的,也有函数来添加新属性:int device_create_file(struct device *, struct device_attribute *);void device_remove_file(struct device *, struct device_attribute *);同理有driver_attribute。