linux笔记3

作者: codercjg | 来源:发表于2016-09-21 16:40 被阅读0次

    make menuconfig过程解析
    作者 codercjg28 九月 2015, 5:27 下午

    make menuconfig用于图形界面配置linux内核。
    linux源码根目录下有.config文件,其他子目录下一般都会有一个Kconfig文件和Makefile文件。
    三个文件的作用分别为:
    Kconfig: 定义配置项
    .config: 设置配置项的值(可通过make menuconfig界面配置或者直接修改)
    Makefile:读取配置项的值,并根据该值决定是否编译该目录下该配置项关联的c源文件

    make menuconfig 首先会读取/arch/arm/Kconfig, 然后根据该Kconfig文件引用其他目录下的Kconfig,
    最后和根目录下的.config对比,生成图形配置界面,配置完成后的结果保存在.config文件中。
    比如当写一个hello的字符驱动hello.c后,放在linux源码/driver/char/目录下后,要一起编译进内核需要
    修改该目录下的Kconfig和Makefile.
    在/driver/char/Kconfig文件里加入以下内容:
    config HELLO
    bool “/dev/hello hello driver example ”
    default y
    help
    Say Y here if you want to support /dev/hello device.
    然后make menuconfig后就可以看到如下内容:



    但这时执行make zImage还不能编译成功,要正确编译还需要在/driver/char/Makefile文件里加上:
    obj-$(CONFIG_HELLO)+= hello.o
    当在make menuconfig图形界面里选中了hello选项后,生成的.config文件会有CONFIG_HELLO=y
    当执行make zImage命令时,obj-y += hello.o 就表示要把该目标文件编译进内核。
    如果是模块,则可把HELLO配置项设为tristate类型,在make menuconfig图形界面选择hello M模块选项时
    生成的.config文件会CONFIG_HELLO=m
    当执行make modules命令时,obj-m +=hell.o就表示把该目标文件编译为模块。
    obj-y和obj-m是linux 编译时定义的全局变量,分别表示要编译进内核的文件列表和编译为模块的文件列表。

    其他相关命令:
    make clean 清除编译内核生成的相关文件
    make distclean 清除编译内核生成的相关文件,并且删除根目录下的.config文件
    make xxxx_defconfig 会根据/arch/arm/configs/目录下的xxx_defconfig配置文件生成根目录下的.config文件。

    分类: Linux驱动 | 评论

    platform总线设备驱动模型
    作者 codercjg28 九月 2015, 3:57 下午

    linux设备驱动模型中分总线、设备、驱动三个重要概念。
    每种设备都要挂在一种总线上,比如MCU外部引脚引出的i2c、spi等,然而在MCU内部的i2c控制器、spi控制器等却不在任何总线上。
    因此,linux抽象出platform总线的概念,MCU内部的各种设备都可挂在platform总线上。
    platform设备驱动的步骤:
    platform_device_register()=>platform_driver_register()=>platform_driver_unregister()=>platform_device_unregister()
    platform设备驱动分为两个:一个平台设备platform_device和一个平台驱动platform_driver。
    下面是一个最简单的platform hello驱动
    hello-device.c源码

    include <linux/module.h>

    include <linux/kernel.h>

    include <linux/platform_device.h>

    void hello_device_release(struct device *dev)
    {
    printk(“hello_device_release\n”);
    }
    struct platform_device hello_device = {
    .name = “hello”,
    .id = -1,
    .dev = {
    .release = hello_device_release,
    },
    };
    static int __init hello_device_init(void)
    {
    int ret;
    printk(“hello_device_init\n”);
    ret = platform_device_register(&hello_device);
    if(ret){
    printk(“platform_device_register failed\n”);
    }
    return ret;
    }
    static void __exit hello_device_exit(void)
    {
    platform_device_unregister(&hello_device);
    printk(“hello_device_exit\n”);
    }
    MODULE_AUTHOR(“codercjg”);
    MODULE_LICENSE(“Dual BSD/GPL”);
    module_init(hello_device_init);
    module_exit(hello_device_exit);
    hello-driver.c源码

    include <linux/module.h>

    include <linux/kernel.h>

    include <linux/platform_device.h>

    int hello_probe(struct platform_device *pdev)
    {
    printk(“hello_probe\n”);
    return 0;
    }
    int hello_remove(struct platform_device *pdev)
    {
    printk(“hello_remove\n”);
    return 0;
    }
    struct platform_driver hello_driver = {
    .probe = hello_probe,
    .remove = hello_remove,
    .driver = {
    .name = “hello”,
    },
    };
    static int __init hello_driver_init(void)
    {
    int ret;
    printk(“hello_driver_init\n”);
    ret = platform_driver_register(&hello_driver);
    if(ret){
    printk(“hello_driver_init failed\n”);
    }
    return ret;
    }
    static void __exit hello_driver_exit(void)
    {
    platform_driver_unregister(&hello_driver);
    printk(“hello_driver_exit\n”);
    }
    MODULE_AUTHOR(“codercjg”);
    MODULE_LICENSE(“Dual BSD/GPL”);
    module_init(hello_driver_init);
    module_exit(hello_driver_exit);
    Makefile源码
    obj-m := hello-device.o hello-driver.o
    KERNELDIR := /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)
    all:
    make -C $(KERNELDIR) M=$(PWD) modules
    .PHONY: clean
    clean:
    rm -rf *.o *.ko
    编译后执行命令:
    sudo inmod ./hello-device.ko
    sudo inmod ./hello-driver.ko
    hello-device和hello-driver通过.name = “hello” 匹配
    之后可在 /sys/bus/platform/devices/和 /sys/devices/platform/下找到hello

    分类: Linux驱动 | 评论

    序列文件seq_file
    作者 codercjg25 九月 2015, 5:16 下午

    seq_file可在/proc下创建一个文件用于表示内核中的数据,用户可以用cat命令打印其内容。
    实现proc文件需要一个向该文件填充内核数据的迭代器seq_operations和用户读写该文件的接口file_operations。
    seq_operations中包含seq_start、seq_show、seq_next、seq_stop等迭代器相关函数。
    file_operations中包含seq_open、seq_read、seq_lseek、seq_release等proc文件操作相关函数,
    这些函数在内核源码/fs/seq_file中有默认实现,通常只需改写seq_open。
    1.源码:

    include <linux/module.h>

    include <linux/kernel.h>

    include <linux/proc_fs.h>

    include <linux/seq_file.h>

    static char* strs[] = {“aa”, “bb”, “c”};
    /* 迭代开始 /
    static void
    seq_start(struct seq_file m, loff_t pos)
    {
    printk(“seq_start\n”);
    if(
    pos >= 3){
    return NULL;
    }
    else {
    pos = 0;
    return strs[
    pos];
    }
    }
    /
    迭代下一个 /
    static void
    seq_next(struct seq_file m, void v, loff_t pos)
    {
    printk(“seq_next\n”);
    if(++
    pos >= 3){
    return NULL;
    }
    else{
    return strs[
    pos];
    }
    }
    /
    迭代结束 */
    static void seq_stop(struct seq_file *m, void v)
    {
    printk(“seq_stop\n”);
    }
    /
    写当前元素到proc文件 */
    static int seq_show(struct seq_file m, void v)
    {
    printk(“seq_show\n”);
    seq_printf(m, “%s”, (char
    )v);
    return 0;
    }
    /
    迭代器 /
    static struct seq_operations seqops = {
    .start = seq_start,
    .next = seq_next,
    .stop = seq_stop,
    .show = seq_show,
    };
    /
    打开proc文件 */
    int my_seq_open(struct inode inode, struct file file)
    {
    printk(“seq_open\n”);
    return seq_open(file, &seqops);
    }
    /
    proc文件操作接口 /
    static struct file_operations fileops = {
    .open = my_seq_open,
    .read = seq_read,
    .llseek = seq_lseek,
    .release = seq_release,
    };
    static int __init myproc_init(void)
    {
    struct proc_dir_entry
    entry;
    entry = proc_create(“myproc”, 777, NULL, &fileops); /
    创建/proc/myproc文件 /
    if(!entry){
    printk(“create /proc/myproc error\n”);
    remove_proc_entry(“myproc”, NULL);
    return -1;
    }
    printk(“create /proc/myproc ok\n”);
    return 0;
    }
    static void __exit myproc_exit(void)
    {
    remove_proc_entry(“myproc”, NULL); /
    删除/proc/myproc文件 */
    printk(“remove /proc/myproc ok\n”);
    }
    MODULE_AUTHOR(“codercjg”);
    MODULE_LICENSE(“Dual BSD/GPL”);
    module_init(myproc_init);
    module_exit(myproc_exit);
    2.查看结果
    sudo inmod seqfile.ko
    sudo cat/proc/myproc
    会打印出aabbcc
    3.查看日志
    tail -f /var/log/syslog查看日志:
    Sep 25 10:41:48 instant-contiki kernel: [ 539.889249] create /proc/myproc ok
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951100] seq_open
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951130] seq_start
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951131] seq_show
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951133] seq_next
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951133] seq_show
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951134] seq_next
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951135] seq_show
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951136] seq_next
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951137] seq_stop
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951249] seq_start
    Sep 25 10:42:05 instant-contiki kernel: [ 556.951250] seq_stop
    Sep 25 10:43:11 instant-contiki kernel: [ 622.739478] remove /proc/myproc ok
    4.总结:
    由源码和日志可知写入myproc文件是通过迭代器用seq_printf()一个元素一个元素的写入,。
    首先调用seq_start()获得第一个元素,然后调用seq_printf()写入myproc文件,
    然后调用seq_next()获取下一个元素,接着调用seq_printf(),直到seq_next()返回NULL后调用seq_stop()迭代结束。
    即seq_start()->seq_show()->seq_next()->seq_show()->…->seq_next()->seq_stop();
    sodu rmmod seqfile后,/proc/myproc文件消失了。

    分类: Linux驱动 | 评论

    linux MISC设备驱动写法
    作者 codercjg23 九月 2015, 4:40 下午

    在编写字符设备驱动过程中,驱动入口函数中常有一些alloc_chrdev_region()分配主次设备号,
    device_create()创建设备节点/dev/xxx,cdev_init()和cdev_add()注册为字符驱动等共性操作。
    而出口函数又需要收回设备号、删除设备节点、卸载字符驱动等。
    为了简化字符设备驱动的编写,出现了MISC设备驱动,它只需要调用misc_register()和misc_deregister()
    即可完成字符设备驱动的入口函数和出口函数相关操作。在linux源码drivers/char/misc.c中可找到misc的具体实现。
    misc设备驱动本质仍为字符设备驱动,只是所有misc设备的主设备号为10,根据次设备号和设备节点名对具体设备进行区分。
    次设备号和设备节点名可在驱动中定义的struct miscdevice变量中指定。

    普通字符设备驱动
    struct class *hello_class;
    int globalfifo_init(void)
    {
    int ret;
    dev_t devno = MKDEV(globalfifo_major, 0);
    if (globalfifo_major) {
    ret = register_chrdev_region(devno, 1, “globalfifo”);
    } else {
    // 动态分配主设备号
    ret = alloc_chrdev_region(&devno, 0, 1, “globalfifo”);
    globalfifo_major = MAJOR(devno);
    }
    if (ret < 0)
    return ret;
    memset(&fifodev, 0, sizeof(struct globalfifo_dev));
    cdev_init(&fifodev.cdev, &globalfifo_fops);
    fifodev.cdev.owner = THIS_MODULE;
    cdev_add(&fifodev.cdev, devno, 1);
    sema_init(&fifodev.sem, 1);
    init_waitqueue_head(&fifodev.r_wait);
    init_waitqueue_head(&fifodev.w_wait);

    // 创建设备节点/dev/byte
    hello_class = class_create(THIS_MODULE, “fifo_class”);
    device_create(hello_class, NULL, MKDEV(globalfifo_major, 0), NULL, “byte”);
    printk(KERN_INFO”fifo_init\n”);
    return 0; // 记得要有返回值,否则insmod的时候会提示出错
    

    }

    void globalfifo_exit(void)
    {
    // 删除设备节点/dev/byte
    device_destroy(hello_class, MKDEV(globalfifo_major, 0));
    class_destroy(hello_class);
    cdev_del(&fifodev.cdev);
    unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1);
    printk(KERN_INFO”fifo_exit\n”);
    }
    module_init(globalfifo_init);
    module_exit(globalfifo_exit);

    misc设备驱动:
    static struct miscdevice misc = {
    ** .minor = MISC_DYNAMIC_MINOR,**
    ** .name = “byte”,**
    ** .fops = &globalfifo_fops,**
    };

    int globalfifo_init(void)
    {
    int ret;
    memset(&fifodev, 0, sizeof(struct globalfifo_dev));
    sema_init(&fifodev.sem, 1);
    init_waitqueue_head(&fifodev.r_wait);
    init_waitqueue_head(&fifodev.w_wait);

    ** ret = misc_register(&misc);**
    printk(KERN_INFO”fifo_init\n”);
    return ret; // 记得要有返回值,否则insmod的时候会提示出错
    }

    void globalfifo_exit(void)
    {
    ** misc_deregister(&misc);**
    }

    sudo insmod ./misc_globafifo.ko后即可找到/dev/byte节点
    执行命令查看生成的设备节点/dev/byte
    ls /dev -al
    crwxrwxrwx 1 root root 10, 57 Sep 10 06:32 byte
    从打印的消息中可以看出字符设备/dev/byte主设备号为10,次设备号为57。

    分类: Linux驱动 | 评论

    sscanf()遇到空格
    作者 codercjg18 九月 2015, 3:50 下午

    sscanf从字符串按某种格式提取参数遇到空格就会停止。
    int a;
    char * str = “hello 123″;
    sscanf(str, “%s%d”, a);
    %
    s可以忽略空格之前的hello

    分类: Linux | 评论

    只有一个字节的linux字符设备驱动
    作者 codercjg9 九月 2015, 3:48 下午

    只有一个字节的字符设备驱动,实现阻塞和非阻塞读写、异步信号通知、select、ioctl等。
    测试系统为ubuntu, 内核为linux3.2 。kernel2.3.36后ioctl变成unlock_ioctl,而且少了一个inode参数。
    编写代码过程中,可以把kernel源码用source insight建一个工程,然后把驱动加入这个工程,这样就能有
    代码提示的功能,而且查看源码也方便,再也不用因记不住函数名和参数烦扰。
    测试过程中可用tail -f /etc/var/syslog 实时查看驱动的打印信息,而不用一遍遍cat /etc/var/syslog了。
    可以用lsmod查看驱动是否已加载,用cat /proc/devices查看设备节点是否创建成功。
    源码下载地址:http://pan.baidu.com/s/1t1Zt0
    驱动源码:

    include <linux/module.h>

    include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/cdev.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/poll.h>#include <linux/device.h>

    define GLOBAL_FIFO_MAJOR 0

    static int globalfifo_major = GLOBAL_FIFO_MAJOR;
    /* 只有一个字节的字符设备/struct globalfifo_dev {struct cdev cdev;unsigned char mem; /一字节缓存/unsigned char full; /可写标志/struct semaphore sem;/ 信号量/wait_queue_head_t r_wait; /读进程等待队列头/wait_queue_head_t w_wait;/写进程等待队列头/struct fasync_struct async_queue; /用于读的异步结构指针/};
    struct globalfifo_dev fifodev;/文件打开函数/int globalfifo_open(struct inode inode, struct file filp){/将设备结构体指针赋值给文件私有数据指针/filp->private_data = &fifodev;return 0;}
    /文件释放函数/int globalfifo_release(struct inode inode, struct file filp){/ 将文件从异步通知列表中删除 /
    return 0;}
    /
    ioctl设备控制函数 /static int globalfifo_ioctl(struct file filp, unsigned int cmd, unsigned long arg){struct globalfifo_dev dev = (struct globalfifo_dev)filp->private_data;switch(cmd){case 1:down(&dev->sem);dev->mem = 0;up(&dev->sem);printk(KERN_INFO”zero mem\n”);break;default:return -EINVAL;}
    return 0;}
    /
    poll函数 /static unsigned int globalfifo_poll(struct file filp, poll_table wait){unsigned int mask = 0;struct globalfifo_dev dev = (struct globalfifo_dev)filp->private_data;printk(KERN_INFO”poll\n”);down(&dev->sem);
    poll_wait(filp, &dev->r_wait, wait);poll_wait(filp, &dev->w_wait, wait);if (dev->full == 1){mask |= POLLIN | POLLRDNORM; /
    标示数据可读
    /}else if (dev->full == 0){mask |= POLLOUT | POLLWRNORM; /
    标示数据可写
    /}
    up(&dev->sem);return mask;}
    /
    globalfifo fasync函数*/static int globalfifo_fasync(int fd, struct file filp, int mode){struct globalfifo_dev dev = filp->private_data;printk(KERN_INFO”fasync_helper\n”);return fasync_helper(fd, filp, mode, &dev->async_queue);}/globalfifo读函数/static ssize_t globalfifo_read(struct file *filp, char __user buf, size_t count,loff_t ppos){int ret = 1;
    printk(KERN_INFO”to read %d\n”, count);struct globalfifo_dev dev = (struct globalfifo_dev)filp->private_data;DECLARE_WAITQUEUE(read, current);add_wait_queue(&dev->r_wait, &read);
    down(&dev->sem);if (dev->full == 0) { // 如果不可读if (filp->f_flags & O_NONBLOCK) {// 非阻塞直接返回ret = -EAGAIN;printk(KERN_INFO”read EAGAIN\n”);goto out;} else {__set_current_state(TASK_INTERRUPTIBLE);while (dev->full == 0) {up(&dev->sem);schedule();if (signal_pending(current)) { // 阻塞时被信号打断ret = -ERESTARTSYS;printk(KERN_INFO”read ERESTARTSYS\n”);goto out;}down(&dev->sem);}// 使用循环原因:可能有多个读进程被唤醒,进行读操作前可能已被其他读进程抢先//所以需要重新判断可读条件}
    }// 读操作if (copy_to_user(buf, &dev->mem, 1)) {ret = -EFAULT;printk(KERN_INFO”read EFAULT\n”);goto out;}
    dev->full = 0;up(&dev->sem);printk(KERN_INFO”wake_up w\n”);wake_up_interruptible(&dev->w_wait); // 唤醒写等待队列中的进程ret = 1;
    out:remove_wait_queue(&dev->r_wait, &read);__set_current_state(TASK_RUNNING);printk(KERN_INFO”read end\n”);
    return ret;}/
    globalfifo写操作
    /static ssize_t globalfifo_write(struct file *filp, const char __user buf,size_t count, loff_t ppos){int ret = 1;
    printk(KERN_INFO”to write %d\n”, count);struct globalfifo_dev dev = (struct globalfifo_dev)filp->private_data;DECLARE_WAITQUEUE(write, current);add_wait_queue(&dev->w_wait, &write);
    down(&dev->sem);if (dev->full == 1) { //如果不可写if (filp->f_flags & O_NONBLOCK) { // 非阻塞直接返回printk(KERN_INFO”write: O_NONBLOCK\n”);ret = -EAGAIN;goto out;} else {__set_current_state(TASK_INTERRUPTIBLE);while (dev->full == 1) {up(&dev->sem);schedule(); // 阻塞进程if (signal_pending(current)) { // 阻塞时被信号打断ret = -ERESTARTSYS;printk(KERN_INFO”write: ERESTARTSYS\n”);goto out;}down(&dev->sem);}// 使用循环原因:可能有多个写进程被唤醒,进行写操作前可能已被其他写进程抢先//所以需要重新判断可写条件}
    }// 写操作if (copy_from_user(&dev->mem, buf, 1) ) {ret = -EFAULT;printk(KERN_INFO”write: EFAULT\n”);goto out;}
    dev->full = 1;up(&dev->sem);printk(KERN_INFO”wake_up r\n”);// 唤醒读等待队列中的进程wake_up_interruptible(&dev->r_wait);ret = 1;// 发送异步信号给读进程if (dev->async_queue)kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
    out:remove_wait_queue(&dev->w_wait, &write);__set_current_state(TASK_RUNNING);printk(KERN_INFO”write end\n”);
    return ret;
    }
    /
    文件操作结构体
    /static const struct file_operations globalfifo_fops = {.owner = THIS_MODULE,.read = globalfifo_read,.write = globalfifo_write,.unlocked_ioctl = globalfifo_ioctl,.poll = globalfifo_poll,.open = globalfifo_open,.release = globalfifo_release,.fasync = globalfifo_fasync,};struct class *hello_class;int globalfifo_init(void){int ret;dev_t devno = MKDEV(globalfifo_major, 0);if (globalfifo_major) {ret = register_chrdev_region(devno, 1, “globalfifo”);} else {// 动态分配主设备号ret = alloc_chrdev_region(&devno, 0, 1, “globalfifo”);globalfifo_major = MAJOR(devno);}if (ret < 0)return ret;memset(&fifodev, 0, sizeof(struct globalfifo_dev));
    cdev_init(&fifodev.cdev, &globalfifo_fops);fifodev.cdev.owner = THIS_MODULE;cdev_add(&fifodev.cdev, devno, 1);sema_init(&fifodev.sem, 1);init_waitqueue_head(&fifodev.r_wait);init_waitqueue_head(&fifodev.w_wait);
    // 创建设备节点/dev/bytehello_class = class_create(THIS_MODULE, “fifo_class”);device_create(hello_class, NULL, MKDEV(globalfifo_major, 0), NULL, “byte”);printk(KERN_INFO”fifo_init\n”);return 0; // 记得要有返回值,否则insmod的时候会提示出错}
    void globalfifo_exit(void){
    // 删除设备节点/dev/bytedevice_destroy(hello_class, MKDEV(globalfifo_major, 0));class_destroy(hello_class);
    cdev_del(&fifodev.cdev);unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1);printk(KERN_INFO”fifo_exit\n”);}
    MODULE_AUTHOR(“codercjg”);MODULE_LICENSE(“Dual BSD/GPL”);
    module_param(globalfifo_major, int, S_IRUGO);
    module_init(globalfifo_init);module_exit(globalfifo_exit);
    编译驱动Makefile:
    obj-m := globalfifo.o
    KERNELDIR := /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)
    all:
    make -C $(KERNELDIR) M=$(PWD) modules
    .PHONY: clean
    clean:
    rm -rf *.o *.ko
    加载驱动脚本:

    !/bin/bash

    sudo insmod ./globalfifo.ko
    sudo chmod 777 /dev/byte
    卸载驱动脚本:

    !/bin/bash

    sudo rm /dev/byte
    sudo rmmod globalfifo
    阻塞写:

    include <unistd.h>

    include <sys/types.h>

    include <sys/stat.h>

    include <fcntl.h>

    include <stdio.h>

    int main(int argc, char **argv)
    {
    int fd;
    ssize_t size;
    char ch;
    if(argc<2){
    printf(“usage: write 1\n”);
    return 1;
    }
    ch = argv[1][0];
    fd = open(“/dev/byte”, O_WRONLY);
    size = write(fd, &ch, 1);
    if(size > 0){
    printf(“%c\n”, ch);
    }else{
    printf(“err\n”);
    }
    close(fd);
    return 0;
    }
    阻塞读:

    include <unistd.h>

    include <sys/types.h>

    include <sys/stat.h>

    include <fcntl.h>

    include <stdio.h>

    int main(void)
    {
    int fd;
    ssize_t size;
    char buf[2];
    fd = open(“/dev/byte”, O_RDONLY);
    size = read(fd, buf, 1);
    if(size > 0){
    printf(“%c\n”, buf[0]);
    }else{
    printf(“err\n”);
    }
    close(fd);
    return 0;
    }
    异步信号读:

    include <unistd.h>

    include <sys/types.h>

    include <sys/stat.h>

    include <fcntl.h>

    include <stdio.h>

    include <signal.h>

    include <sys/ioctl.h>

    int fd;
    char ch;
    void io_handler(int sigio)
    {
    size_t size;
    size = read(fd, &ch, 1);
    if(size > 0){
    printf(“%c\n”, ch);
    }else{
    printf(“err\n”);
    }
    }
    int main(void)
    {
    int flag;
    signal(SIGIO, io_handler);
    fd = open(“/dev/byte”, O_RDONLY);
    if(ioctl(fd, 1)<0){
    perror(“ioctl”);
    return 1;
    }
    fcntl(fd, F_SETOWN, getpid());
    flag = fcntl(fd, F_GETFL);
    flag |= FASYNC;
    fcntl(fd, F_SETFL, flag);
    while(ch != ‘q’);
    close(fd);
    return 0;
    }
    select读:

    include <sys/types.h>

    include <sys/stat.h>

    include <fcntl.h>

    include <stdio.h>

    include <sys/time.h>

    int main(void)
    {
    fd_set inset;
    struct timeval timeout;
    int ret;
    int fd;
    ssize_t size;
    char ch;
    fd = open(“/dev/byte”, O_RDONLY);
    while(1)
    {
    timeout.tv_sec = 2;
    timeout.tv_usec = 0;
    FD_ZERO(&inset);
    FD_SET(fd, &inset);
    ret = select(fd+1, &inset, NULL, NULL, NULL);
    if(ret>0 && FD_ISSET(fd, &inset))
    {
    read(fd, &ch, 1);
    printf(“%c\n”, ch);
    if(ch == ‘q’)
    break;
    } else if(ret==0)
    {
    printf(“time out\n”);
    }else{
    perror(“select”);
    }
    }
    close(fd);
    return 0;
    }

    分类: Linux驱动 | 评论

    实时打印syslog信息
    作者 codercjg8 九月 2015, 5:20 下午

    tail -f /var/log/syslog

    分类: Linux | 评论

    相关文章

      网友评论

        本文标题:linux笔记3

        本文链接:https://www.haomeiwen.com/subject/tcpaettx.html