Linux驱动程序之统计单词个数

0. 需要的头文件、宏及变量
  1 #include <linux/module.h>                                                                                                                                                                               
  2 #include <linux/init.h>
  3 #include <linux/kernel.h>
  4 #include <linux/fs.h>
  5 #include <linux/miscdevice.h>
  6 #include <linux/uaccess.h>
  7 
  8 // 定义一些宏和变量
  9 #define DEVICE_NAME "wordcount"  // 定义设备文件名
 10 static unsigned char mem[10000]; // 保存向设备文件写入的数据
 11 // static char read_flag = 'y';  // y:已从设备文件读取数据 n:未读取数据
 12 static int word_count = 0;  // 单词数 
 13 #define TRUE -1
 14 #define FALSE 0
1. 建立Linux驱动骨架(装载和卸载Linux驱动)

装载

// 初始化Linux驱动                                                                                                                                                       
 static int word_count_init(void)
 {
     int ret;
     // 建立设备文件
     ret = misc_register(&misc);
     // 输出日志信息
     printk("word_count_init_success\n");
     return ret;
 }

卸载

 // 退出Linux驱动
 static void word_count_exit(void)
 {
     // 移除设备文件
     misc_deregister(&misc);
     // 输出日志信息
     printk("word_count_exit_success\n");
   }

注册Linux驱动加载和卸载函数:

module_init(word_count_init);
module_exit(word_count_exit);
2.注册和注销设备文件

指定设备文件信息:

// 描述与设备文件触发的事件对应的回调函数指针                                                                                                                            
// owner:设备事件回调函数应用于哪些驱动模块,THIS_MODULE表示应用于当前驱动模块                                                                                          
// 需要设置read和write成员变量,系统才能调用处理读写设备文件动作的函数                                                                                                   
static struct file_operations dev_fops =                                                                                                                                 
{ .owner = THIS_MODULE, .read = word_count_read, .write = word_count_write };                                                                                            
                                                                                                                                                                        
// 描述设备文件的信息                                                                                                                                                    
// minor: 次设备号  MISC_DYNAMIC_MINOR:动态生成次设备号 name: 设备文件名称                                                                                              
// fops: file_operations结构体变量指针                                                                                                                                   
static struct miscdevice misc =                                                                                                                                          
{ .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops };  

注册和注销动作已于步骤1中通过misc_register和 misc_deregister函数完成。

3. 指定与驱动相关的信息
// 驱动相关信息
MODULE_AUTHOR("LAZIJI");
MODULE_DESCRIPTION("statistics of word count");
MODULE_ALIAS("word count module");
 MODULE_LICENSE("GPL");
4. 编写回调函数

读取设备文件数据的函数

 // file:指向设备文件  buf:保存可读取的数据 count:可读取的字节数  ppos:读取数据的偏移量                                                                               
 static ssize_t word_count_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)                                                                          
 {                                                                                                                                                                        
     unsigned char temp[4];                                                                                                                                               
     // 将单词数(int类型)分解成4个字节存储在buf中                                                                                                                       
     temp[0] = word_count >> 24;                                                                                                                                          
     temp[1] = word_count >> 16;                                                                                                                                          
     temp[2] = word_count >> 8;                                                                                                                                           
     temp[3] = word_count;                                                                                                                                                
     copy_to_user(buf, (void*) temp, 4);                                                                                                                                  
     printk("read:word count:%d", (int) count);                                                                                                                                                                                                                                                                                                     
     return count;                                                                                                                                                                                                                                                                                                                              
 }

向设备文件写数据的函数

 // file:指向设备文件  buf:保存写入的数据 count:写入数据的字节数  ppos:写入数据的偏移量                                                                               
 static ssize_t word_count_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)                                                                   
 {                                                                                                                                                                        
     ssize_t written = count;                                                                                                                                             
                                                                                                                                                                          
     copy_from_user(mem, buf, count);                                                                                                                                     
     mem[count] = '\0';                                                                                                                                                   
     // 统计单词数                                                                                                                                                        
     word_count = get_word_count(mem);                                                                                                                                    
     printk("write:word count:%d", (int) word_count);                                                                                                                     
     return written; 
 }
5.编写业务逻辑

判断字符是否为空格(包括空格符、制表符、回车符和换行符)

 static char is_spacewhite(char c)                                                                                                                                        
 {                                                                                                                                                                        
     if(c == ' ' || c == 9 || c == 13 || c == 10)                                                                                                                         
         return TRUE;                                                                                                                                                     
     else                                                                                                                                                                 
         return FALSE;                                                                                                                                                    
 }

统计单词数

 static int get_word_count(const char *buf)                                                                                                                               
 {                                                                                                                                                                        
     int n = 1;                                                                                                                                                           
     int i = 0;                                                                                                                                                           
     char c = ' ';                                                                                                                                                        
                                                                                                                                                                          
 // 处理多个空格分隔的情况,0:正常情况,1:已遇到一个空格                                                                                             
     if(*buf == '\0')                                                                                                                                                     
         return 0;                                                                                                                                                        
     // 第1个字符是空格,从0开始计数                                                                                                                                      
     if(is_spacewhite(*buf) == TRUE)                                                                                                                                      
         n--;                                                                                                                                                             
     // 扫描字符串中的每一个字符                                                                                                                                          
     for (; (c = *(buf + i)) != '\0'; i++)                                                                                                                                
        {                                                                                                                                                                    
         // 只由一个空格分割单词的情况                                                                                                                                    
         if(flag == 1 && is_spacewhite(c) == FALSE)                                                                                                                       
         {                                                                                                                                                                
             flag = 0;                                                                                                                                                    
         }                                                                                                                                                                
         // 由多个空格分隔单词的情况,忽略多余的空格                                                                                                                      
         else if(flag == 1 && is_spacewhite(c) == TRUE)                                                                                                                   
         {                                                                                                                                                                
             continue;                                                                                                                                                    
         }                                                                                                                                                                
         // 当前字符为空格时单词数加1                                                                                                                                     
         if(is_spacewhite(c) == TRUE)                                                                                                                                     
         {                                                                                                                                                                
             n++;                                                                                                                                                         
             flag = 1;                                                                                                                                                    
         }                                                                                                                                                                
     }                                                                                                                                                                    
     if(is_spacewhite(*(buf + i - 1)) == TRUE)                                                                                                                            
         n--;                                                                                                                                                             
     return n;
 }
6.编写Makefile文件
  1 obj-m := word_count1.o
  2 
  3 PWD := $(shell pwd)                                                                                                                                                                                     
  4 KernelDir :=/lib/modules/$(shell uname -r)/build/
  5    
  6 all:
  7     $(MAKE) -C $(KernelDir) M=$(PWD) modules
  8 
  9 all_install:
 10     $(MAKE) -C $(KernelDir) M=$(PWD) modules_install
 11 
 12 clean:
 13     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers *.order *.mod
 14 .PHOHY: modules modules_install clean
7.编译Linux驱动程序

编译为模块的步骤:将驱动程序和Makefile文件放到同一目录下,将命令行切换到该目录下,输入make完成编译,产生.ko文件。

8.安装和卸载Linux驱动

分别输入insmod + .ko文件和rmmod + .ko文件完成安装和卸载

9. Linux驱动测试

测试程序test.c

  1 #include <stdio.h>                                                                                                                                                                                      
  2 #include <fcntl.h>
  3 #include <unistd.h>
  4 #include <stdlib.h>
  5 #include <string.h>
  6 int main(int argc, char *argv[])
  7 {
  8     int testdev;   // 打开设备文件(/dev/wordcount)的句柄
  9     unsigned char buf[4];  // 表示单词数的4个字节
 10     // 打开设备文件
 11     testdev = open("/dev/wordcount", O_RDWR);
 12     // 如果open函数返回-1,表示打开设备文件失败
 13     if (testdev == -1)
 14     {
 15         printf("Cann't open file \n");
 16         return 0;
 17     }
 18     // 如果test_word_count后面跟有命令行参数,程序会将第1个参数值当做待统计的字符串
 19     // 如果没有命令行参数,则只读取设备文件中的值
 20     if (argc > 1)
 21     {
 22         // 向设备文件写入待统计的字符串
 23         write(testdev, argv[1], strlen(argv[1]));
 24         // 输出待统计的字符串
 25         printf("string:%s\n", argv[1]);
 26     }
 27     // 读取设备文件中的单词数(4个字节)
 28     read(testdev, buf, 4);
 29 
 30     int n = 0; // 单词数
 31 
 32     // 将4个字节还原成int类型的值  
 33     n = ((int) buf[0]) << 24 |((int) buf[1]) << 16 | ((int) buf[2]) << 8 | ((int) buf[3]); 
 34     // 分别输出从设备文件获取的4个字节的值
 35     printf("word byte display:%d,%d,%d,%d\n", buf[0], buf[1], buf[2], buf[3]);
 36     // 输出统计出的单词数
 37     printf("word count:%d\n", n);  
 38     // 关闭设备文件
 39     close(testdev);
 40 
 41     return 0;
 42 }

编译测试代码:在终端输入 gcc test.c -o test
执行测试代码:在终端输入 ./test "la zi ji zhen de la"
终端显示的结果:
string:la zi ji zhen de la
word byte display:0,0,0,6
word count:6

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335