精华内容
下载资源
问答
  • Linux PWM接口

    千次阅读 2018-12-23 22:36:23
    这提供了有关Linux PWM接口的概述 PWM通常用于控制手机中的LED,风扇或振动器。具有固定目的的PWM不需要实现Linux PWM API(尽管它们可以)。然而,PWM通常被发现作为SoC上的分立器件,没有固定的目的。电...

    0.脉冲宽度调制(PWM)接口

    这提供了有关Linux PWM接口的概述

    PWM通常用于控制手机中的LED,风扇或振动器。具有固定目的的PWM不需要实现Linux PWM API(尽管它们可以)。然而,PWM通常被发现作为SoC上的分立器件,没有固定的目的。电路板设计师可以将它们连接到LED或风扇。为了提供这种灵活性,通用PWM API诞生了。


    1.识别PWM

    传统PWM API的用户使用唯一ID来指代PWM设备。

    不应该通过其唯一ID引用PWM器件,电路板设置代码应该注册静态映射,该映射将PWM使用者与提供者匹配,如以下示例中所示。

    static struct pwm_lookup board_pwm_lookup [] = {
    PWM_LOOKUP(“tegra-pwm”,0,“pwm-backlight”,NULL,
    50000,PWM_POLARITY_NORMAL),
    };
    
    static void __init board_init(void)
    {
    ...
    pwm_add_table(board_pwm_lookup,ARRAY_SIZE(board_pwm_lookup));
    ...
    }
    

    2.使用PWM

    传统用户可以使用pwm_request()请求PWM设备,并在使用pwm_free()后将其释放。

    新用户应使用pwm_get()函数请求PWM设备,并将消费者设备(使用者)名称传递给它。 pwm_put()用于释放PWM器件。这些函数的变体,devm_pwm_get()和devm_pwm_put()也存在。

    请求后,必须使用如下API进行PWM配置:

    int pwm_apply_state(struct pwm_device * pwm,struct pwm_state * state);
    
    此API控制PWM周期/ duty_cycle配置和启用/禁用状态。
    

    pwm_config(),pwm_enable()和pwm_disable()函数只是pwm_apply_state()的封装,如果用户想要一次更改多个参数,则不应使用它。例如,如果你看到pwm_config()和pwm_ {enable,disable}()调用同一个函数,这可能意味着你应该改为使用pwm_apply_state()。

    PWM API还允许用户通过pwm_get_state()查询PWM状态。

    除PWM状态外,PWM API还会公开PWM参数,这是在PWM上应该使用的参考PWM配置。PWM参数通常是特定于平台的,并且允许PWM用户仅关注相对于整个周期的占空比(例如,占空比=周期的50%)。struct pwm_args包含2个字段(周期和极性),应该用于设置初始PWM配置(通常在PWM用户探测函数中完成)。使用pwm_get_args()检索PWM参数。


    3.将PWM与sysfs接口配合使用

    如果在内核配置中启用了CONFIG_SYSFS,则会提供一个简单的sysfs接口来使用用户空间的PWM。它在/ sys / class / pwm /中公开。每个被探测的PWM控制器/芯片将被输出为pwmchipN,其中N是PWM芯片的基础。你在目录里面会发现:

      npwm
        该芯片支持的PWM通道数(只读)。
    
      export
        导出用于sysfs的PWM通道(只写)。
    
      unexport
       从sysfs中取消导出PWM通道(只写)。
    

    PWM通道使用从0到npwm-1的每芯片索引编号。

    导出PWM通道时,将在与其关联的pwmchipN目录中创建pwmX目录,其中X是导出的通道编号。然后将提供以下属性:

      period
        PWM信号的总周期(读/写)。
        值以纳秒为单位,是活动和非活动的总和
        PWM的时间。
    
      duty_cycle(占空比)
        PWM信号的有效时间(读/写)。
        值以纳秒为单位,且必须小于周期。
    	在NORMAL模式下,表示一个周期内高电平持续的时间
    	在INVERTED模式下,表示一个周期中低电平持续的时间
      
      polarity
        改变PWM信号的极性(读/写)。
        写入此属性仅在PWM芯片支持更改时才有效
        极性。只有PWM不能改变极性
        启用。值是字符串“normal”或“inversed”。
    
      enable
        启用/禁用PWM信号(读/写)。
    
     -  0  - 禁用
     -  1  - 启用
    

    4.实现PWM驱动程序

    目前有两种方法可以实现pwm驱动程序。以前每个驱动程序必须自己实现pwm _ *()函数。这意味着系统中不可能有多个PWM驱动器。因此,新驱动程序必须使用通用PWM框架。

    可以使用pwmchip_add()添加新的PWM控制器/芯片,并使用pwmchip_remove()再次删除。 pwmchip_add()将填充的struct pwm_chip(PWM芯片的描述、芯片提供的PWM器件数量以及支持的PWM操作的芯片)作为参数,特定实现到框架。

    在PWM驱动器中实现极性支持时,请确保遵守PWM框架中的信号约定。根据定义,正常极性表征信号在占空比持续时间内开始为高电平,在剩余的时间内变低。相反,具有反转极性的信号在占空比的持续时间内开始为低电平,并在该周期的剩余时间内变为高电平。
    在这里插入图片描述
    上图分别为INVERTED和NORMAL模式。

    鼓励驱动程序实现 - > apply()而不是legacy-> enable(), - > disable()和 - > config()方法。这样做应该在PWM配置工作流程中提供原子性,这在PWM控制关键设备(如稳压器)时是必需的。

    由于同样的原因,也鼓励实现 - > get_state()(用于检索初始PWM状态的方法):让PWM用户了解当前的PWM状态将允许他避免毛刺。


    5.锁

    PWM核心列表操作受互斥锁保护,因此可能无法从原子上下文调用pwm_request()和pwm_free()。 目前,PWM内核不对pwm_enable(),pwm_disable()和pwm_config()强制执行任何锁,因此调用上下文当前是特定于驱动程序的。 这是旧API派生的问题,应尽快修复。


    6.求助

    目前,PWM只能配置period_ns和duty_ns。 对于部分情况,freq_hz和duty_percent可能会更好。 请考虑在框架中添加适当的帮助程序,而不是在驱动程序中计算。

    展开全文
  • linux新建/删除接口

    千次阅读 2019-07-22 11:06:29
    安装vconfig apt-get install vconfig ...新建接口vlan vconfig add eth2 3021 配置子接口 ifconfig eth2.3021 18.5.82.53 netmask 255.255.255.0 查看接口ifconfig eth2.3021 Link encap:Ethernet HWaddr...
    1. 安装vconfig
      apt-get install vconfig
    2. 运行802.1q模块
      modprobe 8021q
    3. 新建接口vlan
      vconfig add eth2 3021
    4. 配置子接口
      ifconfig eth2.3021 18.5.82.53 netmask 255.255.255.0
    5. 查看接口ifconfig
      eth2.3021 Link encap:Ethernet HWaddr 00:0b?f3:36:78
      inet addr:18.5.82.53 Bcast:18.5.82.255 Mask:255.255.255.0
      inet6 addr: fe80::20b:abff:fef3:3678/64 Scope:Link
      UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
      RX packets:0 errors:0 dropped:0 overruns:0 frame:0
      TX packets:32 errors:0 dropped:0 overruns:0 carrier:0
      collisions:0 txqueuelen:0
      RX bytes:0 (0.0 B) TX bytes:5440 (5.4 KB)
    6. 子接口down
      ifconfig eth2.3020 down
    7. 接口down后ifconfig查不到子接口,ip add可以看到
      10: eth2.3020@eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default
      link/ether 00:0b?f3:36:78 brd ff:ff:ff:ff:ff:ff
    8. 彻底删除子接口
      ip link delete eth2.3020
      这都是临时生效,重启后失效,要永久生效需要修改配置文件
      /etc/network/interfaces
    展开全文
  • linux proc接口

    千次阅读 2010-12-15 00:22:00
    linux proc接口的建立与使用 /proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux® 内核空间和用户空间之间进行通信。在 /proc 文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行...

    linux proc接口的建立与使用

     /proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux® 内核空间和用户空间之间进行通信。在 /proc 文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段,但是与普通文件不同的是,这些虚拟文件的内容都是动态创建的。

    /proc 文件系统是为了提供有关系统中进程的信息。但是由于这个文件系统非常有用,因此内核中的很多元素也开始使用它来报告信息,或启用动态运行时配置。

    /proc 文件系统包含了一些目录(用作组织信息的方式)和虚拟文件。虚拟文件可以向用户呈现内核中的一些信息,也可以用作一种从用户空间向内核发送信息的手段。

    尽管像本文这样短小的一篇文章无法详细介绍 /proc 的所有用法,但是它依然对这两种用法进行了展示,从而可以让我们体会一下 /proc 是多么强大。清单 1 是对 /proc 中部分元素进行一次交互查询的结果。它显示的是 /proc 文件系统的根目录中的内容。注意,在左边是一系列数字编号的文件。每个实际上都是一个目录,表示系统中的一个进程。由于在 GNU/Linux 中创建的第一个进程是 init 进程,因此它的 process-id1。然后对这个目录执行一个 ls 命令,这会显示很多文件。每个文件都提供了有关这个特殊进程的详细信息。例如,要查看 init 的 command-line 项的内容,只需对 cmdline 文件执行 cat 命令。

    /proc 中另外一些有趣的文件有:cpuinfo,它标识了处理器的类型和速度;pci,显示在 PCI 总线上找到的设备;modules,标识了当前加载到内核中的模块。


    清单 1. 对 /proc 的交互过程
            
    [root@plato]# ls /proc
    1     2040  2347  2874  474          fb           mdstat      sys
    104   2061  2356  2930  9            filesystems  meminfo     sysrq-trigger
    113   2073  2375  2933  acpi         fs           misc        sysvipc
    1375  21    2409  2934  buddyinfo    ide          modules     tty
    1395  2189  2445  2935  bus          interrupts   mounts      uptime
    1706  2201  2514  2938  cmdline      iomem        mtrr        version
    179   2211  2515  2947  cpuinfo      ioports      net         vmstat
    180   2223  2607  3     crypto       irq          partitions
    181   2278  2608  3004  devices      kallsyms     pci
    182   2291  2609  3008  diskstats    kcore        self
    2     2301  263   3056  dma          kmsg         slabinfo
    2015  2311  2805  394   driver       loadavg      stat
    2019  2337  2821  4     execdomains  locks        swaps
    [root@plato 1]# ls /proc/1
    auxv     cwd      exe  loginuid  mem     oom_adj    root  statm   task
    cmdline  environ  fd   maps      mounts  oom_score  stat  status  wchan
    [root@plato]# cat /proc/1/cmdline
    init [5]
    [root@plato]#
    

    清单 2 展示了对 /proc 中的一个虚拟文件进行读写的过程。这个例子首先检查内核的 TCP/IP 栈中的 IP 转发的目前设置,然后再启用这种功能。


    清单 2. 对 /proc 进行读写(配置内核)
            
    [root@plato]# cat /proc/sys/net/ipv4/ip_forward
    0
    [root@plato]# echo "1" > /proc/sys/net/ipv4/ip_forward
    [root@plato]# cat /proc/sys/net/ipv4/ip_forward
    1
    [root@plato]#
    

    另外,我们还可以使用 sysctl 来配置这些内核条目。有关这个问题的更多信息,请参阅 参考资料 一节的内容。

    顺便说一下,/proc 文件系统并不是 GNU/Linux 系统中的惟一一个虚拟文件系统。在这种系统上,sysfs 是一个与 /proc 类似的文件系统,但是它的组织更好(从 /proc 中学习了很多教训)。不过 /proc 已经确立了自己的地位,因此即使 sysfs 与 /proc 相比有一些优点,/proc 也依然会存在。还有一个 debugfs 文件系统,不过(顾名思义)它提供的更多是调试接口。debugfs 的一个优点是它将一个值导出给用户空间非常简单(实际上这不过是一个调用而已)。

    内核模块简介

    可加载内核模块(LKM)是用来展示 /proc 文件系统的一种简单方法,这是因为这是一种用来动态地向 Linux 内核添加或删除代码的新方法。LKM 也是 Linux 内核中为设备驱动程序和文件系统使用的一种流行机制。

    如果您曾经重新编译过 Linux 内核,就可能会发现在内核的配置过程中,有很多设备驱动程序和其他内核元素都被编译成了模块。如果一个驱动程序被直接编译到了内核中,那么即使这个驱动程序没有运行,它的代码和静态数据也会占据一部分空间。但是如果这个驱动程序被编译成一个模块,就只有在需要内存并将其加载到内核时才会真正占用内存空间。有趣的是,对于 LKM 来说,我们不会注意到有什么性能方面的差异,因此这对于创建一个适应于自己环境的内核来说是一种功能强大的手段,这样可以根据可用硬件和连接的设备来加载对应的模块。

    下面是一个简单的 LKM,可以帮助您理解它与在 Linux 内核中看到的标准(非动态可加载的)代码之间的区别。清单 3 给出了一个最简单的 LKM。(可以从本文的 下载 一节中下载这个代码)。

    清单 3 包括了必须的模块头(它定义了模块的 API、类型和宏)。然后使用 MODULE_LICENSE 定义了这个模块使用的许可证。此处,我们定义的是 GPL,从而防止会污染到内核。

    清单 3 然后又定义了这个模块的 initcleanup 函数。my_module_init 函数是在加载这个模块时被调用的,它用来进行一些初始化方面的工作。my_module_cleanup 函数是在卸载这个模块时被调用的,它用来释放内存并清除这个模块的踪迹。注意此处 printk 的用法:这是内核的 printf 函数。KERN_INFO 符号是一个字符串,可以用来对进入内核回环缓冲区的信息进行过滤(非常类似于 syslog)。

    最后,清单 3 使用 module_initmodule_exit 宏声明了入口函数和出口函数。这样我们就可以按照自己的意愿来对这个模块的 initcleanup 函数进行命名了,不过我们最终要告诉内核维护函数就是这些函数。


    清单 3. 一个简单的但可以正常工作的 LKM(simple-lkm.c)
            
    #include <linux/module.h>
    /* Defines the license for this LKM */
    MODULE_LICENSE("GPL");
    /* Init function called on module entry */
    int my_module_init( void )
    {
      printk(KERN_INFO "my_module_init called.  Module is now loaded./n");
      return 0;
    }
    /* Cleanup function called on module exit */
    void my_module_cleanup( void )
    {
      printk(KERN_INFO "my_module_cleanup called.  Module is now unloaded./n");
      return;
    }
    /* Declare entry and exit functions */
    module_init( my_module_init );
    module_exit( my_module_cleanup );
    

    清单 3 尽管非常简单,但它却是一个真正的 LKM。现在让我们对其进行编译并在一个 2.6 版本的内核上进行测试。2.6 版本的内核为内核模块的编译引入了一种新方法,我发现这种方法比原来的方法简单了很多。对于文件 simple-lkm.c,我们可以创建一个 makefile,其惟一内容如下:

    obj-m += simple-lkm.o
    

    要编译 LKM,请使用 make 命令,如清单 4 所示。


    清单 4. 编译 LKM
            
    [root@plato]# make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules
    make: Entering directory `/usr/src/linux-2.6.11'
      CC [M]  /root/projects/misc/module2.6/simple/simple-lkm.o
      Building modules, stage 2.
      MODPOST
      CC      /root/projects/misc/module2.6/simple/simple-lkm.mod.o
      LD [M]  /root/projects/misc/module2.6/simple/simple-lkm.ko
    make: Leaving directory `/usr/src/linux-2.6.11'
    [root@plato]#
    

    结果会生成一个 simple-lkm.ko 文件。这个新的命名约定可以帮助将这些内核对象(LKM)与标准对象区分开来。现在可以加载或卸载这个模块了,然后可以查看它的输出。要加载这个模块,请使用 insmod 命令;反之,要卸载这个模块,请使用 rmmod 命令。lsmod 可以显示当前加载的 LKM(参见清单 5)。


    清单 5. 插入、检查和删除 LKM
            
    [root@plato]# insmod simple-lkm.ko
    [root@plato]# lsmod
    Module                  Size  Used by
    simple_lkm              1536  0
    autofs4                26244  0
    video                  13956  0
    button                  5264  0
    battery                 7684  0
    ac                      3716  0
    yenta_socket           18952  3
    rsrc_nonstatic          9472  1 yenta_socket
    uhci_hcd               32144  0
    i2c_piix4               7824  0
    dm_mod                 56468  3
    [root@plato]# rmmod simple-lkm
    [root@plato]#
    

    注意,内核的输出进到了内核回环缓冲区中,而不是打印到 stdout 上,这是因为 stdout 是进程特有的环境。要查看内核回环缓冲区中的消息,可以使用 dmesg 工具(或者通过 /proc 本身使用 cat /proc/kmsg 命令)。清单 6 给出了 dmesg 显示的最后几条消息。


    清单 6. 查看来自 LKM 的内核输出
            
    [root@plato]# dmesg | tail -5
    cs: IO port probe 0xa00-0xaff: clean.
    eth0: Link is down
    eth0: Link is up, running at 100Mbit half-duplex
    my_module_init called.  Module is now loaded.
    my_module_cleanup called.  Module is now unloaded.
    [root@plato]#
    

    可以在内核输出中看到这个模块的消息。现在让我们暂时离开这个简单的例子,来看几个可以用来开发有用 LKM 的内核 API。


    集成到 /proc 文件系统中

    内核程序员可以使用的标准 API,LKM 程序员也可以使用。LKM 甚至可以导出内核使用的新变量和函数。有关 API 的完整介绍已经超出了本文的范围,因此我们在这里只是简单地介绍后面在展示一个更有用的 LKM 时所使用的几个元素。

    创建并删除 /proc 项

    要在 /proc 文件系统中创建一个虚拟文件,请使用 create_proc_entry 函数。这个函数可以接收一个文件名、一组权限和这个文件在 /proc 文件系统中出现的位置。create_proc_entry 的返回值是一个 proc_dir_entry 指针(或者为 NULL,说明在 create 时发生了错误)。然后就可以使用这个返回的指针来配置这个虚拟文件的其他参数,例如在对该文件执行读操作时应该调用的函数。create_proc_entry 的原型和 proc_dir_entry 结构中的一部分如清单 7 所示。


    清单 7. 用来管理 /proc 文件系统项的元素
            
    struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode,
                                                 struct proc_dir_entry *parent );
    struct proc_dir_entry {
    	const char *name;			// virtual file name
    	mode_t mode;				// mode permissions
    	uid_t uid;				// File's user id
    	gid_t gid;				// File's group id
    	struct inode_operations *proc_iops;	// Inode operations functions
    	struct file_operations *proc_fops;	// File operations functions
    	struct proc_dir_entry *parent;		// Parent directory
    	...
    	read_proc_t *read_proc;			// /proc read function
    	write_proc_t *write_proc;		// /proc write function
    	void *data;				// Pointer to private data
    	atomic_t count;				// use count
    	...
    };
    void remove_proc_entry( const char *name, struct proc_dir_entry *parent );
    

    稍后我们就可以看到如何使用 read_procwrite_proc 命令来插入对这个虚拟文件进行读写的函数。

    要从 /proc 中删除一个文件,可以使用 remove_proc_entry 函数。要使用这个函数,我们需要提供文件名字符串,以及这个文件在 /proc 文件系统中的位置(parent)。这个函数原型如清单 7 所示。

    parent 参数可以为 NULL(表示 /proc 根目录),也可以是很多其他值,这取决于我们希望将这个文件放到什么地方。表 1 列出了可以使用的其他一些父 proc_dir_entry,以及它们在这个文件系统中的位置。


    表 1. proc_dir_entry 快捷变量
    proc_dir_entry在文件系统中的位置
    proc_root_fs/proc
    proc_net/proc/net
    proc_bus/proc/bus
    proc_root_driver/proc/driver

    回调函数

    我们可以使用 write_proc 函数向 /proc 中写入一项。这个函数的原型如下:

    int mod_write( struct file *filp, const char __user *buff,
                   unsigned long len, void *data );
    

    filp 参数实际上是一个打开文件结构(我们可以忽略这个参数)。buff 参数是传递给您的字符串数据。缓冲区地址实际上是一个用户空间的缓冲区,因此我们不能直接读取它。len 参数定义了在 buff 中有多少数据要被写入。data 参数是一个指向私有数据的指针(参见 清单 7)。在这个模块中,我们声明了一个这种类型的函数来处理到达的数据。

    Linux 提供了一组 API 来在用户空间和内核空间之间移动数据。对于 write_proc 的情况来说,我们使用了 copy_from_user 函数来维护用户空间的数据。

    读回调函数

    我们可以使用 read_proc 函数从一个 /proc 项中读取数据(从内核空间到用户空间)。这个函数的原型如下:

    int mod_read( char *page, char **start, off_t off,
                  int count, int *eof, void *data );
    

    page 参数是这些数据写入到的位置,其中 count 定义了可以写入的最大字符数。在返回多页数据(通常一页是 4KB)时,我们需要使用 startoff 参数。当所有数据全部写入之后,就需要设置 eof(文件结束参数)。与 write 类似,data 表示的也是私有数据。此处提供的 page 缓冲区在内核空间中。因此,我们可以直接写入,而不用调用 copy_to_user

    其他有用的函数

    我们还可以使用 proc_mkdirsymlinks 以及 proc_symlink 在 /proc 文件系统中创建目录。对于只需要一个 read 函数的简单 /proc 项来说,可以使用 create_proc_read_entry,这会创建一个 /proc 项,并在一个调用中对 read_proc 函数进行初始化。这些函数的原型如清单 8 所示。


    清单 8. 其他有用的 /proc 函数
            
    /* Create a directory in the proc filesystem */
    struct proc_dir_entry *proc_mkdir( const char *name,
                                         struct proc_dir_entry *parent );
    /* Create a symlink in the proc filesystem */
    struct proc_dir_entry *proc_symlink( const char *name,
                                           struct proc_dir_entry *parent,
                                           const char *dest );
    /* Create a proc_dir_entry with a read_proc_t in one call */
    struct proc_dir_entry *create_proc_read_entry( const char *name,
                                                      mode_t mode,
                                                      struct proc_dir_entry *base,
                                                      read_proc_t *read_proc,
                                                      void *data );
    /* Copy buffer to user-space from kernel-space */
    unsigned long copy_to_user( void __user *to,
                                  const void *from,
                                  unsigned long n );
    /* Copy buffer to kernel-space from user-space */
    unsigned long copy_from_user( void *to,
                                    const void __user *from,
                                    unsigned long n );
    /* Allocate a 'virtually' contiguous block of memory */
    void *vmalloc( unsigned long size );
    /* Free a vmalloc'd block of memory */
    void vfree( void *addr );
    /* Export a symbol to the kernel (make it visible to the kernel) */
    EXPORT_SYMBOL( symbol );
    /* Export all symbols in a file to the kernel (declare before module.h) */
    EXPORT_SYMTAB
    


    通过 /proc 文件系统实现财富分发

    下面是一个可以支持读写的 LKM。这个简单的程序提供了一个财富甜点分发。在加载这个模块之后,用户就可以使用 echo 命令向其中导入文本财富,然后再使用 cat 命令逐一读出。

    清单 9 给出了基本的模块函数和变量。init 函数(init_fortune_module)负责使用 vmalloc 来为这个点心罐分配空间,然后使用 memset 将其全部清零。使用所分配并已经清空的 cookie_pot 内存,我们在 /proc 中创建了一个 proc_dir_entry 项,并将其称为 fortune。当 proc_entry 成功创建之后,对自己的本地变量和 proc_entry 结构进行了初始化。我们加载了 /proc readwrite 函数(如清单 9 和清单 10 所示),并确定这个模块的所有者。cleanup 函数简单地从 /proc 文件系统中删除这一项,然后释放 cookie_pot 所占据的内存。

    cookie_pot 是一个固定大小(4KB)的页,它使用两个索引进行管理。第一个是 cookie_index,标识了要将下一个 cookie 写到哪里去。变量 next_fortune 标识了下一个 cookie 应该从哪里读取以便进行输出。在所有的 fortune 项都读取之后,我们简单地回到了 next_fortune


    清单 9. 模块的 init/cleanup 和变量
            
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/proc_fs.h>
    #include <linux/string.h>
    #include <linux/vmalloc.h>
    #include <asm/uaccess.h>
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
    MODULE_AUTHOR("M. Tim Jones");
    #define MAX_COOKIE_LENGTH       PAGE_SIZE
    static struct proc_dir_entry *proc_entry;
    static char *cookie_pot;  // Space for fortune strings
    static int cookie_index;  // Index to write next fortune
    static int next_fortune;  // Index to read next fortune
    int init_fortune_module( void )
    {
      int ret = 0;
      cookie_pot = (char *)vmalloc( MAX_COOKIE_LENGTH );
      if (!cookie_pot) {
        ret = -ENOMEM;
      } else {
        memset( cookie_pot, 0, MAX_COOKIE_LENGTH );
        proc_entry = create_proc_entry( "fortune", 0644, NULL );
        if (proc_entry == NULL) {
          ret = -ENOMEM;
          vfree(cookie_pot);
          printk(KERN_INFO "fortune: Couldn't create proc entry/n");
        } else {
          cookie_index = 0;
          next_fortune = 0;
          proc_entry->read_proc = fortune_read;
          proc_entry->write_proc = fortune_write;
          proc_entry->owner = THIS_MODULE;
          printk(KERN_INFO "fortune: Module loaded./n");
        }
      }
      return ret;
    }
    void cleanup_fortune_module( void )
    {
      remove_proc_entry("fortune", &proc_root);
      vfree(cookie_pot);
      printk(KERN_INFO "fortune: Module unloaded./n");
    }
    module_init( init_fortune_module );
    module_exit( cleanup_fortune_module );
    

    向这个罐中新写入一个 cookie 非常简单(如清单 10 所示)。使用这个写入 cookie 的长度,我们可以检查是否有这么多空间可用。如果没有,就返回 -ENOSPC,它会返回给用户空间。否则,就说明空间存在,我们使用 copy_from_user 将用户缓冲区中的数据直接拷贝到 cookie_pot 中。然后增大 cookie_index(基于用户缓冲区的长度)并使用 NULL 来结束这个字符串。最后,返回实际写入 cookie_pot 的字符的个数,它会返回到用户进程。


    清单 10. 对 fortune 进行写入操作所使用的函数
            
    ssize_t fortune_write( struct file *filp, const char __user *buff,
                            unsigned long len, void *data )
    {
      int space_available = (MAX_COOKIE_LENGTH-cookie_index)+1;
      if (len > space_available) {
        printk(KERN_INFO "fortune: cookie pot is full!/n");
        return -ENOSPC;
      }
      if (copy_from_user( &cookie_pot[cookie_index], buff, len )) {
        return -EFAULT;
      }
      cookie_index += len;
      cookie_pot[cookie_index-1] = 0;
      return len;
    }
    

    对 fortune 进行读取也非常简单,如清单 11 所示。由于我们刚才写入数据的缓冲区(page)已经在内核空间中了,因此可以直接对其进行操作,并使用 sprintf 来写入下一个 fortune。如果 next_fortune 索引大于 cookie_index(要写入的下一个位置),那么我们就将 next_fortune 返回为 0,这是第一个 fortune 的索引。在将这个 fortune 写入用户缓冲区之后,在 next_fortune 索引上增加刚才写入的 fortune 的长度。这样就变成了下一个可用 fortune 的索引。这个 fortune 的长度会被返回并传递给用户。


    清单 11. 对 fortune 进行读取操作所使用的函数
            
    int fortune_read( char *page, char **start, off_t off,
                       int count, int *eof, void *data )
    {
      int len;
      if (off > 0) {
        *eof = 1;
        return 0;
      }
      /* Wrap-around */
      if (next_fortune >= cookie_index) next_fortune = 0;
      len = sprintf(page, "%s/n", &cookie_pot[next_fortune]);
      next_fortune += len;
      return len;
    }
    

    从这个简单的例子中,我们可以看出通过 /proc 文件系统与内核进行通信实际上是件非常简单的事情。现在让我们来看一下这个 fortune 模块的用法(参见清单 12)。


    清单 12. 展示 fortune cookie LKM 的用法
            
    [root@plato]# insmod fortune.ko
    [root@plato]# echo "Success is an individual proposition.  
              Thomas Watson" > /proc/fortune
    [root@plato]# echo "If a man does his best, what else is there?  
                    Gen. Patton" > /proc/fortune
    [root@plato]# echo "Cats: All your base are belong to us.  
                          Zero Wing" > /proc/fortune
    [root@plato]# cat /proc/fortune
    Success is an individual proposition.  Thomas Watson
    [root@plato]# cat /proc/fortune
    If a man does his best, what else is there?  General Patton
    [root@plato]#
    

    /proc 虚拟文件系统可以广泛地用来报告内核的信息,也可以用来进行动态配置。我们会发现它对于驱动程序和模块编程来说都是非常完整的。

    例如:

    1,/proc/cmdline 的例子

    static int cmdline_proc_show(struct seq_file *m, void *v)
    {
     seq_printf(m, "%s/n", saved_command_line);
     return 0;
    }

    static int cmdline_proc_open(struct inode *inode, struct file *file)
    {
     return single_open(file, cmdline_proc_show, NULL);
    }

    static const struct file_operations cmdline_proc_fops = {
     .open  = cmdline_proc_open,
     .read  = seq_read,
     .llseek  = seq_lseek,
     .release = single_release,
    };

    static int __init proc_cmdline_init(void)
    {
     proc_create("cmdline", 0, NULL, &cmdline_proc_fops);
     return 0;
    }

     

    2, 在proc目录产生pdc子目录和led,lcd文件

    static int __init led_create_procfs(void)
    {
     struct proc_dir_entry *proc_pdc_root = NULL;
     struct proc_dir_entry *ent;

     if (led_type == -1) return -1;

     proc_pdc_root = proc_mkdir("pdc", 0);
     if (!proc_pdc_root) return -1;
     proc_pdc_root->owner = THIS_MODULE;
     ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
     if (!ent) return -1;
     ent->data = (void *)LED_NOLCD; /* LED */
     ent->read_proc = led_proc_read;
     ent->write_proc = led_proc_write;
     ent->owner = THIS_MODULE;

     if (led_type == LED_HASLCD)
     {
      ent = create_proc_entry("lcd", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
      if (!ent) return -1;
      ent->data = (void *)LED_HASLCD; /* LCD */
      ent->read_proc = led_proc_read;
      ent->write_proc = led_proc_write;
      ent->owner = THIS_MODULE;
     }

     return 0;
    }

     

     

     

     

    其实自己一直感觉linux系统中的proc接口很好用,不需要写应用程序就可以测试那些驱动接口,只需要在超级终端中敲入命令,爽。今天把一直以来寄存在其他程序中的proc接口移植到自己的程序中,自己写了个proc接口,分享一下。

    #include <linux/proc_fs.h>-----这个库文件必须
    要在/proc目录下建立一个proc接口,需要调用create_proc_entry这个函数,〕
    eg:
    void test_proc_create(void)
    {
     proc_test_cmd = create_proc_entry("test",S_IWUSR,NULL);
     if (proc_expgpio_cmd)
       proc_test_cmd->write_proc = write_proc_test_cmd;
    }
    这个短短的函数就是用来在/proc目录下建立一个test,如果你用命令
    ehco command > /proc/test
    的话,就会调用到write_proc_test_cmd中,当然这个echo语句是可以传递参数进去的,
    echo command parm1 parm2 > /proc/test
     
    今天我的代码中,我是通过parm1来选择不同的函数,用来测试不同的驱动接口,通过parm2甚至parm3等等用来传递参数到驱动接口,这样就间接地调用到了驱动接口中。
    展开全文
  • 重用Linux loopback接口地址

    千次阅读 2017-04-29 21:00:29
    loopback接口Linux系统中特殊的虚拟接口,通常不需要对地址和掩码进行特殊设置。由于项目特殊需求,需要使用此网段地址作(127.x.0.0/16)作为设备内部板卡间通信管理地址使用,因此需要对loopback接口的地址和掩码...

    简介

    loopback接口是Linux系统中特殊的虚拟接口,通常不需要对地址和掩码进行特殊设置。由于项目特殊需求,需要使用此网段地址作(127.x.0.0/16)作为设备内部板卡间通信管理地址使用,因此需要对loopback接口的地址和掩码进行修改。本文在Ubuntu系统中进行方案的验证。

    loopback接口简介

    TCP/IP协议中Lookback接口是一个通过软件实现的虚拟网络接口,它不与任何硬件相关联。
    RFC2606中明确指出了loopback地址的标准域名为localhost。在IPv4中,其对应的IP地址一直是127.0.0.1;理论上,整个127 IP段(127.0.0.0~127.255.255.255)的IP地址都为loopback地址,与localhost对应。在IPv6中,localhost对应的IP地址为0:0:0:0:0:0:0:1,一般写作::1。
    [root@localhost ~]# ifconfig lo
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              inet6 addr: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
    
    [root@localhost ~]# cat /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

    loopback地址和掩码修改

    IP协议规定loopback数据包是不允许在网络中传输的,网络网络接口必须丢弃接收到的loopback数据包。要想改变此缺省规则,需要对loopback地址的判断规则进行修改,对内核进行修改和定制:
    diff --git a/include/linux/in.h b/include/linux/in.h
    index d60122a..32d52db 100644
    --- a/include/linux/in.h
    +++ b/include/linux/in.h
    @@ -238,7 +238,7 @@ struct sockaddr_in {
     
     /* Address to loopback in software to local host.  */
     #define	INADDR_LOOPBACK		0x7f000001	/* 127.0.0.1   */
    -#define	IN_LOOPBACK(a)		((((long int) (a)) & 0xff000000) == 0x7f000000)
    +#define	IN_LOOPBACK(a)		((((long int) (a)) & 0xffff0000) == 0x7f000000)
     
     /* Defines for Multicast INADDR */
     #define INADDR_UNSPEC_GROUP   	0xe0000000U	/* 224.0.0.0   */
    @@ -254,7 +254,7 @@ struct sockaddr_in {
     
     static inline bool ipv4_is_loopback(__be32 addr)
     {
    -	return (addr & htonl(0xff000000)) == htonl(0x7f000000);
    +	return (addr & htonl(0xffff0000)) == htonl(0x7f000000);
     }
     
     static inline bool ipv4_is_multicast(__be32 addr)
    在内核的include/linux/in.h中对loopback地址的掩码进行修改,并修改了loopback地址的判断。按照上述修改,仅127.0.0.0-127.0.255.255为loopback地址,其余127.1.0.0-127.255.255.255均可作为正常接口地址使用。
    配置修改完需要对内核进行重新编译与安装。新内核启动后,可以对loopback地址掩码进行修改:
    [root@localhost ~]# ifconfig lo netmask 255.255.0.0
    [root@localhost ~]# ifconfig lo
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.255.0.0
              inet6 addr: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:16436  Metric:1
              RX packets:4812 errors:0 dropped:0 overruns:0 frame:0
              TX packets:4812 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:2394109 (2.3 MB)  TX bytes:2394109 (2.3 MB)

    配置VLAN子接口

    添加VLAN子接口需要安装VLAN包:
    [root@localhost ~]# apt-get install vlan
    在当前的eth1接口上添加vlan11的子接口,并配置127.11.x.x网段地址。
    [root@localhost ~]# vconfig add eth1 11
    [root@localhost ~]# ifconfig eth1.11 127.11.254.1 netmask 255.255.0.0
    [root@localhost ~]# ifconfig vlan11
    vlan11    Link encap:Ethernet  HWaddr 00:0c:29:22:cf:ac  
              inet addr:127.11.254.1  Bcast:127.11.255.255  Mask:255.255.0.0
              inet6 addr: fe80::20c:29ff:fe22:cfac/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1496  Metric:1
              RX packets:246546 errors:0 dropped:0 overruns:0 frame:0
              TX packets:933262 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:21837553 (21.8 MB)  TX bytes:3719833865 (3.7 GB)
    在虚拟化环境下,我们可以通过virtual switch来连接两个Linux系统,验证此vlan11接口之间的通信。

    接口配置文件

    根据上述对loopback接口的修改,最终相关的接口配置文件如下:
    [root@localhost ~]# cat /etc/network/interfaces
    auto lo
    iface lo inet loopback
            address 127.0.0.1
            netmask 255.255.0.0
            network 127.0.0.0
            broadcast 127.0.255.255
    
    auto vlan11
    iface vlan11 inet static
            address 127.11.254.1
            netmask 255.255.0.0
            network 127.11.0.0
            broadcast 127.11.255.255
            mtu 1496
            vlan_raw_device eth1
    进行到这里,系统已经开始支持127.x.x.x/16的接口地址,相关的报文可以通过网口发出。

    loopback接口掩码加载问题的规避

    在实际测试中,发现系统重启后,loopback地址掩码并不能正常加载,仍为255.0.0.0。这应该是由于NetworkManager加载/etc/network/interfaces配置时,忽略了用户的配置导致。为规避这个问题,可以在/etc/rc.local中对loopback地址的掩码进行配置,在/etc/rc.local中追加下面的语句:
    ifconfig lo netmask 255.255.0.0
    展开全文
  • linux接口设置方法

    千次阅读 2010-02-22 17:41:00
    linux接口设置方法一、 设置接口ip地址1. ipv4地址1) 查看接口配置命令:ifconfig 查看所有接口的配置ifconfig [接口名] 查看指定接口的配置例子:[root@TESTBED1 ~]# ifconfigeth0 Link encap:Ethernet
  • linux 删除IP地址

    万次阅读 2017-09-08 12:24:38
    1. 删除IP地址ip addr del 10.0.0.136 dev eth2参考: 1.linux增加/删除虚拟IP地址
  • 操作系统实验一:Linux命令接口

    千次阅读 2020-07-28 17:29:46
    通过本实验,要求学生熟练掌握Linux各种文件操作命令,包括:使用控制字符执行特殊功能;使用file和strings命令确定文件类型;使用cat利more命令显示文本文件的内容;使用head和tail命令显示文本文件的部分内容;...
  • linux驱动程序接口

    千次阅读 2017-03-16 18:31:03
    1. Linux驱动程序接口 系统调用是操作系统内核与应用程序之间的接口,设备驱动程序则是操作系统内核与机器硬件的接口。几乎所有的系统操作最终映射到物理设备,除了CPU、内存 和少数其它设备,所有的设备控制操作都...
  • Linux网络接口和VLAN配置

    千次阅读 2017-04-18 21:23:24
    查看udev的man手册,在udev的使用上各个发行版没有差别,毕竟使用的都是Linux内核,udev管理配置计算机所有可以称之为设备的设备,网络接口设备(俗称网卡)只是其中之一,udev使用所谓的rules文件描述和记录设备...
  • Linux内核编程接口函数

    万次阅读 2013-03-10 16:12:18
    Linux内核编程接口函数 转载请注明出处: http://blog.csdn.net/drivelinux/article/details/8656280 字符设备相关函数 1.alloc_chrdev_region() 功能: 自动分配一个主设备号及基于此主设备号的若干个连续的指定...
  • Linux删除文件过程解析

    千次阅读 2019-03-16 15:29:35
    当我们执行rm命令删除一个文件的时候,在操作系统底层究竟会发生些什么事情呢,带着这个疑问,我们在Linux-3.10.104内核下对ext4文件系统下的rm操作进行分析。rm命令本身比较简单,但其在内核底层涉及到VFS操作、ext...
  • Linux 删除多余IP地址

    千次阅读 2019-12-21 00:25:17
    1:执行 ip addr 显示如下 2: 修改 ifcfg-ens文件 执行 vi /etc/sysconfig/network-scripts/ifcfg-ens37 3:修改 dhclient.leases ...执行/var/lib/dhcpclient/dhclient.leases ...5:执行 dhclient 从新获取i...
  • Linux中的lo回环接口

    万次阅读 2017-01-20 14:39:20
    linux的lo接口
  • linux 读写文件接口

    千次阅读 2013-06-17 23:41:56
    linux中,计算机将时间的概念抽象为进程,将空间的概念抽象成文件。 1.文件描述符 linux为每一个打开的文件在内核中建立一个文件表项,该文件表项包括文件的状态信息,存储文件内容的缓冲区,当前文件的读写...
  • linux 文件删除过程浅析

    千次阅读 2016-05-14 17:43:54
    1.Linux文件删除原理 Linux是通过link的数量控制文件删除的,只有当文件不存在任何链接时,该文件才会被删除,一般每个文件有两个link计数器: i_count 和 i_nlink,从VFS inode结构体中可以找到: struct inode {...
  • Linux内核加密接口分析

    千次阅读 2010-11-26 20:19:00
    一、概述   Linux内核从2.5版本开始引入了强力的加密机制,主要原因有:删除冗余代码、支持IPSec协议以及通用的加密功能等。将来的应用会包括:硬件加密设备驱动、内核代码签名、硬件随机数生成器、...
  • Linux C 删除文件夹

    千次阅读 2013-12-17 09:53:38
    方法一: #include   #include   #include   ...方法二.... -r 就是向下递归,不管有多少级目录,一并删除  -f 就是直接强行删除,不作任何提示的意思 
  • linux系统调用接口整理

    千次阅读 2016-03-10 20:58:00
     以下是Linux系统调用的一个...这可能是你在互联网上所能看到的唯一一篇中文注释的Linux系统调用列表,即使是简单的字母序英文列表,能做到这么完全也是很罕见的。  按照惯例,这个列表以man pages第2节,即
  • 为了突出讲解的方便性,我把以前工作中珍藏的一些实验过程贡献给大家。(未经允许,请勿转载) 一.实验目的 1. 了解Linux操作系统的启动与... 熟悉操作系统的命令接口、图形接口和程序接口的区别与联系 5.了解命令行
  • linux删除主ip,从ip自动被删除

    千次阅读 2016-04-15 13:42:32
    2.删除主ip 30.1.1.1/24 后接口配置如下 [root@sangfor ~]# ip addr show eth0 379: eth0: ,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 500  link/ether 28:51:32:03:4a:...
  • 0c:29:d9:25:86 arp 1”字样,查看当前网卡的mac地址发现不是该地址,使用“man iftab”了解iftab文件的作用后删除改行,同时修改/etc/network/interfaces文件中相应的接口的ip地址配置。重启系
  • Linux iptables 防火墙 添加删除 端口

    千次阅读 2018-04-27 16:04:57
    Linux iptables 防火墙 添加删除 端口 具体网址:http://blog.csdn.net/tianlesoftware/article/details/6208985 一. Linux 防火墙的启动和关闭 1.1 启动命令 [root@singledb ~]# service iptables stop(关闭...
  • linux删除乱码文件名

    千次阅读 2012-10-18 15:13:33
    linux删除乱码文件名 当文件名为乱码的时候,无法通过键盘输入文件名,所以在终端下就不能直接利用rm,mv等命令管理文件了。 但是我们知道每个文件都有一个i节点号,我们可以考虑通过i节点号来...
  • Linux面试题(2020最新版)

    万次阅读 多人点赞 2020-03-01 11:14:38
    文章目录Linux 概述什么是LinuxUnix和Linux有什么区别?什么是 Linux 内核?Linux的基本组件是什么?Linux 的体系结构BASH和DOS之间的基本区别是什么?Linux 开机启动过程?Linux系统缺省的运行级别?Linux 使用的...
  • 2.发现一个14G的nohup.out文件,使用 rm -rf命令删除发现一个14G的nohup.out文件,使用 rm -rf命令删除 3.在根目录”/”下, 执行 “du -sh”命令,结果为 5.2G, 执行”df -hl”命令,结果仍是使用100%。 ...
  • linux删除网卡信息,重新设置网卡

    万次阅读 2015-12-16 09:34:09
    centos系统删除多余网卡的方法 一、删除系统中中多余的ifcfg-eth0.bak Centos系统更改网卡或网卡MAC地址后会出现个eth0.bak配置备份文件 解决方法: /etc/sysconfig/networking/devices目录下,将ifcfg-...
  • Linux卸载/删除多余网卡

    万次阅读 2016-09-24 11:21:50
    卸载 使用命令ifconfig命令查看网卡情况 确认自己使用的是哪一块网卡,然后把其它的网卡都卸载掉。 运行命令ifconfig 网卡名称 down。 如: ifconfig eth1 down ...删除 ... 一、删除VM中多余的ifcfg
  • linux删除超过指定时间天数的文件

    千次阅读 2017-10-09 23:25:02
    场景 现在流行的云服务器自身所附带的...有些访问频繁的接口/页面很快就会将自身的磁盘给填充满。如何解决这种问题,又保证日志文件不丢失?网上一搜就会有很多解决方案。 以前见过有人将日志文件定期同步到dropbox,腾
  • 关于Linux 环回接口lo的IP地址修改

    万次阅读 2015-10-16 13:52:08
    linux lo接口的IP地址修改有些特殊。 一般接口比如eth0, 我们可以采用vi /etc/sysconfig/network-scripts/ifcfg-eth0进行修改。 但lo接口的IP地址,却无法通过vi /etc/sysconfig/network-scripts/ifcfg-lo来修改...
  • 基于linux下的高级网络接口设置

    千次阅读 2018-05-25 00:27:47
    根据选择的绑定模式,通道绑定两个或者更多个网络接口作为一个网络接口,d 网络的设置 允许管理员使用bonding内核模块和称为通道绑定接口的特殊网络接口将多个网络接口绑定到从而增加带宽和/提供冗余性 模式0 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 217,702
精华内容 87,080
关键字:

linux删除接口

linux 订阅