当前位置: 首页 > 工具软件 > uclinux > 使用案例 >

uCLinux 驱动开发初步

段干弘扬
2023-12-01

uClinux 驱动开发初步

 

uClinux linux 的驱动开发是一致的 , 只是调试的方式不一样,学习 uClinux 的驱动开发也就是学习 linux 驱动开发的过程。 linux 驱动的调试需要至少一台电脑,外加像GDB KDBG 这样的源码级的内核调试工具,如果装一个虚拟机的话,那么只需要一台电脑即可了,但这样对电脑的性能有更高的要求。对于像 uClinux 的驱动调试,则最好是有开发板,也可以用模拟器。在ARM芯片上的移植是uClinux的一个重要应用。而最常用的仿真 ARM 的模拟器有国人开发的开源软件 skyeye ,不仅可以仿真 ARM 内核,并对以ARM作为内核的芯片作了进一步的支持。 可以用skyeye -h 开查看skyeye能仿真的ARM芯片。当然,也可以对 skyeye 作一些扩展以满足自己的要求。以下是如何在 uClinux 添加驱动的过程。

一、编写一个简单的字符驱动程序

//---------------------------------------------mydevice.c-------------------------------------------

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <asm/uaccess.h>

MODULE_LICENSE("GPL");

#define MAJOR_NUM 254 // 主设备号

#define DRIVER_NAME "mydevice"

static ssize_t mydevice_read(struct file *, char *, size_t, loff_t*);

static ssize_t mydevice_write(struct file *, const char *, size_t, loff_t*);

// 初始化字符设备驱动的 file_operations 结构体

struct file_operations mydevice_fops =

{

      .read = mydevice_read,

      .write = mydevice_write,

};

static int global_var = 0; //"mydevice" 设备的全局变量

 

int  mydevice_init(void)

{

      int ret;

      // 注册设备驱动

      printk("<0> mydevice_init /n");

      ret = register_chrdev(MAJOR_NUM,DRIVER_NAME,&mydevice_fops);

      printk("<0> register_chr_dev return %d /n",ret);

      if (ret < 0)

      {

           printk("<0>mydevice register failed /n");

      }

      else

      {

           printk("<0>mydevice register success /n");

      }

      return ret;

}

void mydevice_exit(void)

{

      printk("<0>mydevice_exit!/n");

      unregister_chrdev(MAJOR_NUM,DRIVER_NAME);

}

static ssize_t mydevice_read(struct file *filp,char *buf,size_t len,loff_t *off)

{

      //copy global_var from kernel space to user space

      if(copy_to_user(buf,&global_var,sizeof(int)))

      {

           return -EFAULT;

      }

      return sizeof(int);

}

static ssize_t mydevice_write(struct file *filp,const char *buf,size_t len,loff_t *off)

{

      //copy data from user sapce to kernel space

      if(copy_from_user(&global_var,buf,sizeof(int)))

      {

           return -EFAULT;

      }

      return sizeof(int);

}

//-----------------------------------------------------------------------------------------------------------------

二、将驱动静态编译进 uClinux 内核

要将一个写好的驱动加入 uClinux, 需要对配置文件和 Makefile 作一些修改,由于我们的这个驱动程序是作为一个字符型驱动程序,我们把 mydevice.c 拷到 (uClinux 目录 )/(linux 内核目录 )/drivers/char 目录下。并对这个目录下的 Config.in Makefile 以及 mem.c 作一些修改。

1、         修改 Config.in:

comment   'Character devices' 这行底下加上以下一行:

bool   'support for mydevice'   CONFIG_MYDEVICE   y

2、         修改 Makefile

#

# uClinux drivers

#

下加上以下内容 :

obj-$(CONFIG_MYDEVICE) += mydevice.o

3、         修改 mem.c

mem.c 主要是初始化一些以虚拟设备,这些设备通常是以内存作为基础“设备”的,我们把 mydevice 的初始化代码加入其中:

mem.c 文件的起始位置加上以下代码:

#ifdef CONFIG_MYDEVICE

extern int mydevice_init(void);

#endif

修改 mem.c chr_dev_init 函数     

if (devfs_register_chrdev(MEM_MAJOR,"mem",&memory_fops))

       printk("unable to get major %d for memory devs/n", MEM_MAJOR);

  memory_devfs_register();

  rand_initialize();

#ifdef CONFIG_MYDEVICE

  mydevice_init();

#endif

#ifdef CONFIG_I2C

  i2c_init_all();

#endif

 

4、         编译 mydevice 驱动

所有要作的修改就是这么简单,接下来的问题就是怎样将我们的驱动编译进内核了

(1) 配置内核

运行 make menuconfig

进入 Kernel/Library/Defaults Selection 菜单

选上 Customize Kernel Settings

退出并保存设置

在新出现的菜单中进入 Character devices 子菜单

选上 support for mydevice

退出并保存设置

make dep make 命令生成内核镜像和内存文件系统镜像

 

三、测试我们的驱动

      如何与我们的驱动打交道呢,答案当然是建立一个应用程序了,在《学习笔记之二》中已经详细讲解了如何将一个应用程序加入 uClinux ,现在我们就来看看怎样在应用程序里调用我们的驱动。

   为了让我们驱动能够为应用程序所用,必须事先创建一个文件结点,在通用 linux 系统中我们可以用 mknod 命令,建立的结点会出现在 /dev 目录下。但是在嵌入式 linux 系统 uClinux 中,更好的办法是让 uClinux 在启动时为我们做这些事:

打开( uClinux 目录) /vendors/GDB/ARMulator-EB 目录下的 Makefile 文件,作些修改 , 如下:

( 注:请根据配置时在 Vendor/Product Selection 菜单里的选择来选择 vendors 下的相应 Makefile)

DEVICES = /

      mydevice,c,254,0 /

      tty,c,5,0      console,c,5,1      cua0,c,5,64      cua1,c,5,65  /

其中 mydevice,c,254,0 就是我们添加的内容,各项的含义分另是:

mydevice   : 设备名

c                : 字符设备

254           :主设备号

0                            :副设备号

 

 

下面来看看我们的测试程序 :

//----------------------------------hello.c--------------------------------------

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#include <fcntl.h>

int main(void)

{

      int fd,num;

      fd = open("/dev/mydevice",O_RDWR,S_IRUSR | S_IWUSR);

      if(fd != -1 )

      {

           read(fd,&num,sizeof(int));

           printf("The globalvar is %d /n",num);

           printf("please input the num written to globalvar /n");

           scanf("%d",&num);

           write(fd,&num,sizeof(int));

           read(fd,&num,sizeof(int));

           printf("the globalvar is %d /n",num);

           close(fd);

      }

      else

      {

           printf("device open failure /n");

      }

}

这段代码应该很好理解,首先打开设备,然后写入再读出来

配置好后重新编译内核,用 skyeye 仿真

 

 

 

到此,我们已经开始 uClinux 驱动开发之旅了

 

参考资料:

http://dev.yesky.com/186/2623186.shtml

 

 

转自http://blog.csdn.net/I2Cbus/archive/2008/08/26/2834849.aspx

 类似资料: