嵌入式设备驱动程序设计

设计一个程序,在用户空间的用户应用程序中产生20个随机数,通过内核空间的设备驱动程序按五行四列的排列输出,并显示能被5整除的数。

分析:要实现这个功能需要做以下工作:


1.编写嵌入式设备驱动程序:实现按五行四列的排列输出,并显示能被5整除的数。

1设主设备号为100,即#define data_MAJOR 100

2在函数data_read()中将用户空间通过参数buf传递来的数据按5行4列的排列输出。在使用printk函数时,输出的格式用“%d”。

3在函数data_write()中找出用户空间通过参数buf传递来的能被5整除的数据输出到屏幕上。在使用printk函数时,输出的格式用“%d”。

4使用Vi编辑器编辑一个设备驱动程序data_drv.c。

/*************************************

*设备驱动程序data_drv.c

*由用户应用程序传递20个数值,在本设备驱动程序中进行排列输出,

*并打印出能被5整除的数

*************************************/

#include<linux/config.h>

#include<linux/kernel.h>

#include<linux/init.h>

#include<linux/devfs_fs_kernel.h>

#include<linux/module.h>

#define data_MAJOR 100

ssize_t data_read(struct file * file,char *buf,size_tcount, loff_t* f_ops)

{//将用户空间通过参数buf传递来的数据按5行4列的排列输出

      printk("data_read[--kernel--]\n");

      for(count=0;count<20;count++){

          printk("%d ",buf[count]);

          if((count+1)%4==0)

             printk("\n");

   }

      returncount;

}

ssize_t data_write(struct file * file, const char*buf, size_t count, loff_t * f_ops)

{//找出用户空间通过参数buf传递来的能被5整除的数据

      printk("data_write[--kernel--]\n");

      for(count=0;count<20;count++){

         if(buf[count]%5==0)

            printk("%d ",buf[count]);

   }

return count;

}

int data_open(struct inode * inode, struct file *file)

{

      printk("data_open[--kernel--]\n");

      MOD_INC_USE_COUNT;

      return 0;

}

int data_release(struct inode * inode, struct file *file)

{

      printk("data_release[--kernel--]\n");

      MOD_DEC_USE_COUNT;

      return 0;

}

struct file_operations Test_ctl_ops=

{

      open:     data_open,

      read:      data_read,

      write:     data_write,

release:  data_release,

};

static int __init HW_Test_CTL_init()

{

      int ret =-1;  

      ret =devfs_register_chrdev(data_MAJOR," data_drv",&Test_ctl_ops);

      if(ret <0){  

             printk("data_modulefailed with %d\n[--kernel--]",ret);        

             returnret;    

      }    

      else {

             printk("data_driverregister success!!![--kernel--]\n");   

      }    

      printk("\n...\nret=%x\n...\n",ret);  

      return ret;

}

static int __init data_Test_CTL_init()

{

      int ret =-1;

      printk("data_Test_CTL_init[--kernel--]\n");

      ret=HW_Test_CTL_init();     

      if(ret)           

             returnret;    

      return 0;

}

static void __exit cleanup_Test_ctl()

{

      printk("cleanup_INT_ctl[--kernel--]\n");   

      devfs_unregister_chrdev(data_MAJOR,"data_drv");

}

module_init(data_Test_CTL_init);

module_exit(cleanup_Test_ctl);

2.编写用户测试程序:实现产生20个随机数并调用设备驱动程序硬件实现按五行四列的排列输出,并显示能被5整除的数。

根据题目要求,使用rand()函数产生20个随机数,存入到数组num[20]中(num定义成字符数组,如下:char num[20];),并通过调用设备驱动程序的read()、write()接口函数,将数据传入到内核空间的设备驱动程序中。把在/dev目录下建立的设备文件(设备进入点)设定为data_drv。

使用Vi编辑器编辑一个用户应用程序data_app.c。

用户应用程序中需要用到的函数(本题中不用ioctl函数):

在Linux系统中,I/O设备的存取是通过一组固定的入口点来进行,这组入口点是由每个设备的设备驱动程序提供的。一般来说,字符型设备驱动程序能够提供如下几个入口点。

(1)open——打开设备准备I/O操作,其调用格式为:

int open(char * filename, int access);

open()函数打开成功,返回值就是文件描述符(或文件描述字)的值(非负值),否则返回-1。该函数表示按access的要求打开名为filename的文件,返回值为文件描述符。access的取值请参看详细的open()函数说明,这里access的取值为O_RDWR,表示“读写”。

(2)close——关闭由open()函数打开的文件,其调用格式为:

int close(int handle);

该函数关闭文件描述符handle相连的文件。

(3)read——从设备上读数据,其调用格式为:

int read(int handle, void* buf, int count);

该函数从handle(文件描述符)相连的文件中,读取count个字节放到buf所指的缓冲区中,返回值为实际所读字节数,返回-1表示出错,返回0表示文件结束。

注意:在本程序中需要通过buf传递数组,因此read函数中的参数count为0。

(4)write——往设备上写数据,其调用格式为:

int write(int handle, void *buf, int count);

该函数把count个字节从buf指向的缓冲区中写入与handle相连的文件中,返回值为实际写入的字节数。

注意:在本程序中需要通过buf传递数组,因此write函数中的参数count为0。

(5)ioctl——执行读、写以外的操作,其调用格式为:

int ioctl(int fd, int cmd, …);

参数cmd不经修改地传递给驱动程序,可选的参数都以unsigned long的形式传递给驱动程序。

/************************************************************

*    用户程序data_app.c

************************************************************/

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<fcntl.h>

#define DEVICE_NAME "/dev/data_drv"

int main()

{

char num[20];

int i=0;

for(i=0;i<20;i++)

       num[i]=rand();

      intfd;                                  //声明文件描述符

      intret;                                 //记录关闭设备的返回值

      char *i;

      printf("\nstartdata_driver test\n\n");   

      fd =open(DEVICE_NAME,O_RDWR);  //调用打开设备函数

      printf("fd=%d\n",fd);

      if(fd ==-1){

             printf("opendevice %s error\n",DEVICE_NAME);

      }    

      else {    

             write(fd,num,0);    //调用驱动程序的写操作接口函数

             read(fd,num,0);  //调用驱动程序的读操作接口函数

             ret=close(fd);             //若ret的值为0,表示设备成功关闭

             printf("ret= %d\n",ret);  

             printf("closedata_drive test\n");

      }

      return 0;

}

3.加载和卸载设备驱动程序模块:将设备驱动程序模块动态加载到内核中,输出完成后,从内核中卸载。

(1)为设备驱动程序编写Makefile文件,命名为Makefile,生成data_drv.o。

注意:在虚拟机上编写的Makefile文件要运行在虚拟机上,因此Makefile的前两行为:

INCLUDEDIR =/usr/src/linux-2.4.20-8/include

CC = gcc

(2)编译和运行程序

1在虚拟机上编译和运行程序

1编译设备驱动程序

make

2编译用户应用程序

gcc–o data_app data_app.c

3在虚拟机的/dev目录下,建立设备入口点并查看:

mknod/dev/data_drv c 100 0

ls–l /dev |grep data_drv

4加载设备驱动程序

insmoddata_drv.o

5运行用户应用程序

./data_app

注意:因为使用printk函数将数据输出到/var/log/messages文件中,因此使用cat/var/log/messages查看按照5行4列输出的数据和被5整除的数据。

2在开发板上编译和运行程序

1修改Makefile文件

因为下载到开发板上运行,需要使用armv4l-unknown-linux-gcc编译器,将Makefile的前两行修改为:

INCLUDEDIR= /opt/host/armv4l/include

CC= armv4l-unknown-linux-gcc

2编译设备驱动程序

make

3编译用户应用程序

armv4l-unknown-linux-gcc–o data_app data_app.c

4将上述编译后的用户应用程序data_app和设备驱动程序data_drv.o通过mount命令下载到嵌入式系统开发板上。

mount-t nfs –o nolock 192.168.221.140:/arm2410s/cwsaqdrv  /mnt

5在开发板的/dev目录下,建立设备入口点:

mknod/dev/data_drv c 100 0

6加载设备驱动程序

insmoddata_drv.o

7运行用户应用程序

./data_app

注意:输出显示在超级终端中。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值