开发可统计单词个数的Android驱动程序(3)

发布者:平和宽容最新更新时间:2024-10-21 来源: cnblogs关键字:Android  驱动程序 手机看文章 扫描二维码
随时随地手机看文章

八、 指定回调函数

      本节讲的内容十分关键。不管Linux驱动程序的功能多么复杂还是多么“酷”,都必须允许用户空间的应用程序与内核空间的驱动程序进行交互才有意义。而最 常用的交互方式就是读写设备文件。通过file_operations.read和file_operations.write成员变量可以分别指定读写 设备文件要调用的回调函数指针。

     在本节将为word_count.c添加两个函数:word_count_read和word_count_write。这两个函数分别处理从设备文件读 数据和向设备文件写数据的动作。本节的例子先不考虑word_count要实现的统计单词数的功能,先用word_count_read和 word_count_write函数做一个读写设备文件数据的实验,以便让读者了解如何与设备文件交互数据。本节编写的word_count.c文件是 一个分支,读者可在word_count/read_write目录找到word_count.c文件。可以用该文件覆盖word_count目录下的同 名文件测试本节的例子。

     本例的功能是向设备文件/dev/wordcount写入数据后,都可以从/dev/wordcount设备文件中读出这些数据(只能读取一次)。下面先看看本例的完整的代码。

#include  
#include  
#include  
#include  
#include  
#include  
   
#define DEVICE_NAME 'wordcount'         //  定义设备文件名 
static unsigned char mem[10000];                //  保存向设备文件写入的数据 
static char read_flag = 'y';                    //  y:已从设备文件读取数据   n:未从设备文件读取数据 
static int written_count = 0;                   // 向设备文件写入数据的字节数 
   
//  从设备文件读取数据时调用该函数 
//  file:指向设备文件、buf:保存可读取的数据   count:可读取的字节数  ppos:读取数据的偏移量 
static ssize_t word_count_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 
{    
    //  如果还没有读取设备文件中的数据,可以进行读取 
    if(read_flag == 'n') 
    {    
        //  将内核空间的数据复制到用户空间,buf中的数据就是从设备文件中读出的数据 
        copy_to_user(buf, (void*) mem, written_count); 
        //  向日志输出已读取的字节数 
        printk('read count:%d', (int) written_count); 
        //  设置数据已读状态 
        read_flag = 'y'; 
        return written_count; 
    } 
    //  已经从设备文件读取数据,不能再次读取数据 
    else 
    {    
        return 0; 
    } 
//  向设备文件写入数据时调用该函数 
//  file:指向设备文件、buf:保存写入的数据   count:写入数据的字节数  ppos:写入数据的偏移量 
static ssize_t word_count_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 
{    
    //  将用户空间的数据复制到内核空间,mem中的数据就是向设备文件写入的数据 
    copy_from_user(mem, buf, count); 
    //  设置数据的未读状态 
    read_flag = 'n'; 
    //  保存写入数据的字节数 
    written_count = count; 
    //  向日志输出已写入的字节数 
    printk('written count:%d', (int)count); 
    return count; 
//  描述与设备文件触发的事件对应的回调函数指针 
//  需要设置read和write成员变量,系统才能调用处理读写设备文件动作的函数 
static struct file_operations dev_fops = 
{ .owner = THIS_MODULE, .read = word_count_read, .write = word_count_write }; 
   
//  描述设备文件的信息 
static struct miscdevice misc = 
{ .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops }; 
   
//  初始化Linux驱动 
static int word_count_init(void) 
    int ret; 
    //  建立设备文件 
    ret = misc_register(&misc); 
    //  输出日志信息 
    printk('word_count_init_successn'); 
    return ret; 
   
// 卸载Linux驱动 
static void word_count_exit(void) 
    //  删除设备文件 
    misc_deregister(&misc); 
    //  输出日志信息 
    printk('word_init_exit_successn'); 
   
//  注册初始化Linux驱动的函数 
module_init( word_count_init); 
//  注册卸载Linux驱动的函数 
module_exit( word_count_exit); 
   
MODULE_AUTHOR('lining'); 
MODULE_DESCRIPTION('statistics of word count.'); 
MODULE_ALIAS('word count module.'); 
MODULE_LICENSE('GPL'); 

 

编写上面代码需要了解如下几点。

1. word_count_read和word_count_write函数的参数基本相同,只有第2个参数buf稍微一点差异。 word_count_read函数的buf参数类型是char*,而word_count_write函数的buf参数类型是const char*,这就意味着word_count_write函数中的buf参数值无法修改。word_count_read函数中的buf参数表示从设备文 件读出的数据,也就是说,buf中的数据都可能由设备文件读出,至于可以读出多少数据,取决于word_count_read函数的返回值。如果 word_count_read函数返回n,则可以从buf读出n个字符。当然,如果n为0,表示无法读出任何的字符。如果n小于0,表示发生了某种错误 (n为错误代码)。word_count_write函数中的buf表示由用户空间的应用程序写入的数据。buf参数前有一个“__user”宏,表示 buf的内存区域位于用户空间。

2. 由于内核空间的程序不能直接访问用户空间中的数据,因此,需要在word_count_read和word_count_write函数中分别使用 copy_to_user和copy_from_user函数将数据从内核空间复制到用户空间或从用户空间复制到内核空间。

3. 本例只能从设备文件读一次数据。也就是说,写一次数据,读一次数据后,第二次无法再从设备文件读出任何数据。除非再次写入数据。这个功能是通过 read_flag变量控制的。当read_flag变量值为n,表示还没有读过设备文件,在word_count_read函数中会正常读取数据。如果 read_flag变量值为y,表示已经读过设备文件中的数据,word_count_read函数会直接返回0。应用程序将无法读取任何数据。

4. 实际上word_count_read函数的count参数表示的就是从设备文件读取的字节数。但因为使用cat命令测试word_count驱动时。直 接读取了32768个字节。因此count参数就没什么用了(值总是32768)。所以要在word_count_write函数中将写入的字节数保存, 在word_count_read函数中直接使用写入的字节数。也就是说,写入多少个字节,就读出多少个字节。

5.  所有写入的数据都保存在mem数组中。该数组定义为10000个字符,因此写入的数据字节数不能超过10000,否则将会溢出。

      为了方便读者测试本节的例子,笔者编写了几个Shell脚本文件,允许在UbuntuLinux、S3C6410开发板和Android模拟器上测试 word_count驱动。其中有一个负责调度的脚本文件build.sh。本书所有的例子都会有一个build.sh脚本文件,执行这个脚本文件就会要 求用户选择将源代码编译到那个平台,选择菜单如图6-11所示。用户可以输入1、2或3选择编译平台。如果直接按回车键,默认值会选择第1个编译平台 (UbuntuLinux)。

build.sh脚本文件的代码如下:

source /root/drivers/common.sh 
#  select_target是一个函数,用语显示图6-11所示的选择菜单,并接收用户的输入 
#  改函数在common.sh文件中定义 
select_target 
if [ $selected_target == 1 ]; then 
    source ./build_ubuntu.sh            # 执行编译成Ubuntu Linux平台驱动的脚本文件 
elif [ $selected_target == 2 ]; then     
    source ./build_s3c6410.sh           # 执行编译成s3c6410平台驱动的脚本文件 
elif [ $selected_target == 3 ]; then 
    source ./build_emulator.sh          # 执行编译成Android模拟器平台驱动的脚本文件 
fi 

      在build.sh脚本文件中涉及到了3个脚本文件(build_ubuntu.sh、build_s3c6410.sh和 build_emulator.sh),这3个脚本文件的代码类似,只是选择的Linux内核版本不同。对于S3C6410和Android模拟器平台, 编译完后Linux驱动,会自动将编译好的Linux驱动文件(*.so文件)上传到相应平台的/data/local目录,并安装Linux驱动。例 如,build_s3c6410.sh脚本文件的代码如下:

source /root/drivers/common.sh 
# S3C6410_KERNEL_PATH变量是适用S3C6410平台的Linux内核源代码的路径, 
# 该变量以及其它类似变量都在common.sh脚本文件中定义 
make  -C $S3C6410_KERNEL_PATH  M=${PWD} 
find_devices  
#  如果什么都选择,直接退出  
if [ '$selected_device' == '' ]; then  
    exit 
else     
    #  上传驱动程序(word_count.ko) 
    adb -s $selected_device push ${PWD}/word_count.ko /data/local 
    # 判断word_count驱动是否存在 
    testing=$(adb -s $selected_device shell lsmod | grep  'word_count') 
    if [ '$testing' != '' ]; then 
        #  删除已经存在的word_count驱动 
        adb -s $selected_device shell rmmod word_count 
    fi 
    #  在S3C6410开发板中安装word_count驱动  
    adb -s $selected_device shell 'insmod /data/local/word_count.ko' 
fi 

 

使用上面的脚本文件,需要在read_write目录建立一个Makefile文件,内容如下:

obj-m := word_count.o

现在执行build.sh脚本文件,选择要编译的平台,并执行下面的命令向/dev/word_count设备文件写入数据。

# echo ‘hello lining’ > /dev/wordcount

然后执行如下的命令从/dev/word_count设备文件读取数据。

# cat /dev/wordcount

如果输出“hello lining”,说明测试成功。

 注意:如 果在S3C6410开发板和Android模拟器上测试word_count驱动,需要执行shell.sh脚本文件或adb shell命令进入相应平台的终端。其中shell.sh脚本在/root/drivers目录中。这两种方式的区别是如果有多个Android设备和 PC相连时,shell.sh脚本会出现一个类似图6-11所示的选择菜单,用户可以选择进入哪个Android设备的终端,而adb shell命令必须要加-s命令行参数指定Android设备的ID才可以进入相应Android设备的终端。

九、实现统计单词数的算法

      本节开始编写word_count驱动的业务逻辑:统计单词数。本节实现的算法将由空格、制表符(ASCII:9)、回车符(ASCII:13)和换行符 (ASCII:10)分隔的字符串算做一个单词,该算法同时考虑了有多个分隔符(空格符、制表符、回车符和换行符)的情况。下面是word_count驱 动完整的代码。在代码中包含了统计单词数的函数get_word_count。

#include  
#include  
#include  
#include  
#include  
#include  
   
#define DEVICE_NAME 'wordcount'     //  定义设备文件名 
static unsigned char mem[10000];        // 保存向设备文件写入的数据 
static int word_count = 0;                  //  单词数 
#define TRUE -1 
#define FALSE 0 
   
//  判断指定字符是否为空格(包括空格符、制表符、回车符和换行符) 
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 = ' '; 
   
    char flag = 0;   // 处理多个空格分隔的情况,0:正常情况,1:已遇到一个空格 
    if(*buf == '') 
        return 0; 
    //  第1个字符是空格,从0开始计数 
    if(is_spacewhite(*buf) == TRUE) 
        n--; 
    //  扫描字符串中的每一个字符 
    for (; (c = *(buf + i)) != ''; 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; 
        } 
    } 
    //  如果字符串以一个或多个空格结尾,不计数(单词数减1) 
    if(is_spacewhite(*(buf + i - 1)) == TRUE) 
        n--; 
    return n; 
//  从设备文件读取数据时调用的函数 
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; 
//  向设备文件写入数据时调用的函数 
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] = ''; 
    //  统计单词数 
    word_count = get_word_count(mem); 
    printk('write:word count:%d', (int)word_count); 
    return written; 
   
//  描述与设备文件触发的事件对应的回调函数指针 
static struct file_operations dev_fops = 
{ .owner = THIS_MODULE, .read = word_count_read, .write = word_count_write }; 
   
//  描述设备文件的信息 
static struct miscdevice misc = 
{ .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops }; 
   
//  初始化Linux驱动 
static int word_count_init(void) 
    int ret; 
    //  建立设备文件 
    ret = misc_register(&misc); 
    //  输出日志信息 
    printk('word_count_init_successn'); 
    return ret; 
   
// 卸载Linux驱动 
static void word_count_exit(void) 
    //  删除设备文件 
    misc_deregister(&misc); 
    //  输出日志信息 
    printk('word_init_exit_successn'); 
   
//  注册初始化Linux驱动的函数 
module_init( word_count_init); 
//  注册卸载Linux驱动的函数 
module_exit( word_count_exit); 
   
MODULE_AUTHOR('lining'); 
MODULE_DESCRIPTION('statistics of word count.'); 
MODULE_ALIAS('word count module.'); 
MODULE_LICENSE('GPL'); 

 编写word_count驱动程序需要了解如下几点。

[1] [2]
关键字:Android  驱动程序 引用地址:开发可统计单词个数的Android驱动程序(3)

上一篇:Android培训班(86)内核运行之前的引导程序
下一篇:开发可统计单词个数的Android驱动程序(2)

推荐阅读最新更新时间:2024-11-07 11:12

MIPS与Intrinsic-ID合作为移动平台增加安全性
美普思科技公司 (MIPS Technologies, Inc) 与 Intrinsic-ID 日前共同宣布,双方已携手为移动设备提供顶级的安全性。通过这项合作,MIPS 授权客户和 OEM 厂商能在其平台上实现极具吸引力的安全相关应用,包括媒体内容保护、安全付款交易和安全云存储等。 Intrinsic-ID 的安全 IP 是以专利的硬件既有安全性 (Hardware Intrinsic Security, HIS) 技术为基础,已获得智能卡、汽车、FPGA 和政府应用等领域领先厂商的肯定。MIPS 和 Intrinsic-ID 将在 2012 年 2 月 27 日至 3 月 1 日在西班牙巴塞罗那举行的全球移动通信大会上展示在
[网络通信]
华为超HTC索尼LG摩托 成欧洲第二大Android品牌
     华为 凤凰科技讯 北京时间11月4日消息,据科技网站9to5Google报道,过去数个月华为在全球市场上的成功一直被“大书特书”。在中国市场上,华为超过小米成为第一大智能手机厂商;在全球市场上,它成为销量仅次于三星和苹果的第三大智能手机厂商。华为在全球市场上的成功,似乎在很大程度上归功于它在欧洲的表现。 市场研究公司Kantar Worldpanel今天发表报告称,华为超过索尼、HTC和摩托罗拉成为欧洲五大市场上第二大最流行的Android设备厂商。今年第三季度,华为在欧洲主要市场的排名由一年前的第六位上升到第二位,设备销量仅次于三星。欧洲五大市场指英国、德国、法国、意大利和西班牙。 Kantar World
[手机便携]
搜狐视频新版IOS、安卓客户端上线 强化社交和云端服务
  2012年11月8日消息,今天上午,搜狐视频正式对外宣布,针对苹果iPhone和iPad最新版本的IOS客户端以及Android客户端产品全新上线,新版本除了延续之前第三方登录、定制push、离线下载、3D转换等贴心功能之外,还专门强化了社交与云存储功能,并进一步推广搜狐视频热播大剧、美剧、王牌综艺等广为好评的栏目。   据搜狐视频移动客户端相关负责人介绍,全新推出的IOS版本可以自动上传手机相册、视频,并存储到云端,为用户提供更为安全、便捷的云端存储功能。此外,搜狐视频iPhone升级版本还在UI界面细节进行了便捷用户观影的改变。使得客户端内容呈现更直观、扩展性更强,操作更加简便。   (搜狐视频iPad新版页面截图
[家用电子]
搜狐视频新版IOS、<font color='red'>安卓</font>客户端上线 强化社交和云端服务
中国批准谷歌收购Moto 要求Android免费5年
据商务部网站公告消息,北京时间5月20日,商务部批准谷歌收购摩托罗拉移动,但条件是,谷歌Android操作系统必须在未来5年内继续保持免费和开放。来自新浪科技的消息称,谷歌已同意至少在未来5年内保持Android系统免费,以此换取中国监管部门对谷歌收购摩托罗拉移动交易的批准。 在扫清这笔125亿美元收购交易的最后一个障碍后,预计该交易将于下周早些时候完成。这笔交易于去年8月宣布,需要获得包括中国在内的多个国家监管部门的通过。 如今全球有2.5亿部手机搭载谷歌Android系统,其中包括来自摩托罗拉的设备。Android今后5年的最新版本都必须保持免费和开放,因为监管部门担心如果谷歌优先向摩托罗拉提供新版系统而拒绝向其他厂商提
[手机便携]
升级安卓 11 Beta,一加 8/Pro 新增了一键切换黑暗模式
IT之家6月14日消息 外媒9to5 Google 报道,在升级安装 Android 11 Beta 后,一加8和一加8 Pro 手机获得了专用的一键切换黑暗模式功能。 此前一加承诺在 OxygenOS 更新中带来专用的黑暗模式切换。尽管从技术上讲这并不是为大众设计的真正的 OxygenOS 构建版本,但它仍然为你提供了一加8系列智能手机的新功能选择。 一加8手机的黑暗模式切换开关位于快速设置面板中。每次当你要使设备主题变暗时,这无疑省去了进入主题设置的繁琐过程。 你必须启用它才能访问,功能完全符合用户期望 - 切换仅会相应地激活或停用。 IT之家网友注意,我们仍然不建议你在一加8/Pro 主用手机上下载并安装 Androi
[手机便携]
CyanogenMod创始人加入三星欲增强Android
      “我们总是不知疲倦的等待最新的 Android 更新。CyanogenMod 团队几乎每天都在更新源代码。不过为啥就一直没有公司聘用Cyanogen(让它参与手机制造)呢?”        这是一种普遍的想法,你可能在一些Android博客评论中看到过,所以可能这并不是十分令人惊奇的。三星移动刚刚聘请了Steve Kondik,CyanogenMod创始人,该消息是从Steve的Facebook发布的,目前还没有公布更进一步的消息。        CyanogenMod 自 2009 年首发以来一直持续更新并成为了最流行的 ROM(据统计在 Android 设备上已经安装了 50 万次),可能远远不只这个数值。
[手机便携]
英特尔Atom引入Android 支持所有系统
据国外媒体报道,英特尔软件和服务集团总经理雷妮·詹姆斯(Renee James)周二在英特尔开发者论坛(IDF)上表示,英特尔已经在基于凌动(Atom)处理器的智能手机中引入谷歌Android操作系统。   詹姆斯称,英特尔已经将Android移植到配置Atom处理器的智能手机上,已有客户对此表示兴趣,不过她并未透露更多细节,也未透露目前,英特尔还没有透露能够支持Android操作系统的Atom处理器的具体上市时间。   詹姆斯同时表示,英特尔已经使配置Atom处理器的手机支持现有全部操作系统。   英特尔正在智能手机中推广凌动处理器,此次将Android移植到Atom手机上是整个策略中的一部分。智能手机的每种处理器架
[手机便携]
压制Android 诺基亚微软授权市场杀气重
    据国外媒体报道,英国金融时报晚间报导,诺基亚首席执行官斯蒂芬埃洛普在接受专访时表示,诺基亚与微软拥有许多手机专利,双方将携手向从事侵权行为的竞争对手索取专利授权费。诺基亚,微软在专利授权市场磨刀霍霍,应该是冲着谷歌Android操作系统而来。     微软首席执行官史蒂夫鲍尔默去年10月在接受华尔街日报专访时指出,Android的使用厂商得付专利授权费,绝不是Android货真价实的免费软体。他说,Android的手机厂商宏达电已经跟微软签订授权协议,这部份的专利费收入对微软来说也是一项机会。     微软于2010年4月28日宣布与宏达电签订专利授权协议,微软当时表示该协议涵盖宏达电旗下Android平台手机,宏达电
[手机便携]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved