linux筆記3

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

make menuconfig用于圖形界面配置linux內核。
linux源碼根目錄下有.config文件,其他子目錄下一般都會有一個Kconfig文件和Makefile文件。
三個文件的作用分別為:
Kconfig: 定義配置項
.config: 設置配置項的值(可通過make menuconfig界面配置或者直接修改)
Makefile:讀取配置項的值,并根據該值決定是否編譯該目錄下該配置項關聯(lián)的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后就可以看到如下內容:



但這時執(zhí)行make zImage還不能編譯成功,要正確編譯還需要在/driver/char/Makefile文件里加上:
obj-$(CONFIG_HELLO)+= hello.o
當在make menuconfig圖形界面里選中了hello選項后,生成的.config文件會有CONFIG_HELLO=y
當執(zhí)行make zImage命令時,obj-y += hello.o 就表示要把該目標文件編譯進內核。
如果是模塊,則可把HELLO配置項設為tristate類型,在make menuconfig圖形界面選擇hello M模塊選項時
生成的.config文件會CONFIG_HELLO=m
當執(zhí)行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
編譯后執(zhí)行命令:
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下創(chuàng)建一個文件用于表示內核中的數據,用戶可以用cat命令打印其內容。
實現(xiàn)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中有默認實現(xiàn),通常只需改寫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); /
創(chuàng)建/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()創(chuàng)建設備節(jié)點/dev/xxx,cdev_init()和cdev_add()注冊為字符驅動等共性操作。
而出口函數又需要收回設備號、刪除設備節(jié)點、卸載字符驅動等。
為了簡化字符設備驅動的編寫,出現(xiàn)了MISC設備驅動,它只需要調用misc_register()和misc_deregister()
即可完成字符設備驅動的入口函數和出口函數相關操作。在linux源碼drivers/char/misc.c中可找到misc的具體實現(xiàn)。
misc設備驅動本質仍為字符設備驅動,只是所有misc設備的主設備號為10,根據次設備號和設備節(jié)點名對具體設備進行區(qū)分。
次設備號和設備節(jié)點名可在驅動中定義的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 {
// 動態(tài)分配主設備號
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);

// 創(chuàng)建設備節(jié)點/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)
{
// 刪除設備節(jié)點/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節(jié)點
執(zhí)行命令查看生成的設備節(jié)點/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 | 評論

只有一個字節(jié)的linux字符設備驅動
作者 codercjg9 九月 2015, 3:48 下午

只有一個字節(jié)的字符設備驅動,實現(xiàn)阻塞和非阻塞讀寫、異步信號通知、select、ioctl等。
測試系統(tǒng)為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查看設備節(jié)點是否創(chuàng)建成功。
源碼下載地址: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;
/* 只有一個字節(jié)的字符設備/struct globalfifo_dev {struct cdev cdev;unsigned char mem; /一字節(jié)緩存/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);}// 使用循環(huán)原因:可能有多個讀進程被喚醒,進行讀操作前可能已被其他讀進程搶先//所以需要重新判斷可讀條件}
}// 讀操作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);}// 使用循環(huán)原因:可能有多個寫進程被喚醒,進行寫操作前可能已被其他寫進程搶先//所以需要重新判斷可寫條件}
}// 寫操作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;// 發(fā)送異步信號給讀進程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 {// 動態(tài)分配主設備號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);
// 創(chuàng)建設備節(jié)點/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){
// 刪除設備節(jié)點/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 | 評論

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容