uclinux很久前笔记12

字符设备驱动

一、gpio

gpio驱动:

/********************************gpio.h****************************************/
#ifndef __GPIO_H
#define __GPIO_H
#include 
 
#define MAGIC 0xd0
#define SET _IO(MAGIC,0)
#define CLR _IO(MAGIC,1)
#define OUT _IO(MAGIC,2)
#define MAXNR 3
#endif
/********************************gpio.c****************************************/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "gpio.h"
 
#define GPIO_MAJOR126
#define DEVICE_NAME "gpio"
#define MAX_PORT 1
#define PORTC_CTL_ADDR 0x01d20010
#define PORTC_DAT_ADDR 0x01d20014
static int gpio_open(struct inode*inode,struct file *filp)
{
       MOD_INC_USE_COUNT;
       return0;
}
static int gpio_release(struct inode*inode,struct file *filp)
{
       MOD_DEC_USE_COUNT;
       return0;
}
static int gpio_ioctl(struct inode*inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
       intnum;
       volatileu32 *regctl,*regdat;
       num= MINOR(inode->i_rdev);
       if(num >=MAX_PORT) return -ENODEV;
 
       if(_IOC_TYPE(cmd)!=MAGIC)
              return-ENOTTY;
       if(_IOC_NR(cmd)>=MAXNR)
              return-ENOTTY;
 
       regctl=(volatileu32 *)(PORTC_CTL_ADDR);
       regdat=(volatileu32 *)(PORTC_DAT_ADDR);
       switch(cmd)
       {
           case SET:
              if(arg< 16)
              *regdat|= 1u<
分析:

#define module_init(x) __initcall(x);

#define __initcall(fn)                                                      \

       staticinitcall_t __initcall_##fn __init_call = fn

typedef int (*initcall_t)(void);

#define __init_call  __attribute__ ((unused,__section__ (".initcall.init")))

module_init(gpio_init);

替换:

#define__initcall(gpio_init)                \

       static initcall_t __initcall_ gpio_init  \

__attribute__ ((unused,__section__ (".initcall.init"))) = gpio_init

如果没有属性,该宏定义为:

static initcall_t__initcall_ gpio_init = gpio_init; //这就是一般的静态变量定义并初始化其值。

在vmlinux.lds中:

              ……

              __initcall_start = .;

                     *(.initcall.init)

              __initcall_end = .;

static void __init do_initcalls(void)
{
       initcall_t*call;
       call= &__initcall_start;
       do{
              (*call)();
              call++;
       }while (call < &__initcall_end);
       flush_scheduled_tasks();
}
static void __init do_basic_setup(void)
{
       ……
       sock_init();
       start_context_thread();
       do_initcalls();
       ……
}
static int init(void* unused)
{
       structfiles_struct *files;
       lock_kernel();
       do_basic_setup();
       ……
}

添加模块到内核中:

在2.4内核下的配置(在2.6中不是config.in而是kconfig)

a、 在对应驱动程序所在目录下的config.in文件中添加配置菜单项

格式:编译类型菜单项名称配置变量如:bool ‘gpio_drive’ CONFIG_GPIO

配置结果保存在对应版本linux内核目录(/uCLinux-xxx/linux-2.4.x)下的.config文件中

如:CONFIG_GPIO=y/CONFIG_GPIO=n/CONFIG_GPIO=M(编译成模块)

b、 在对应驱动程序所在目录下的Makefile文件中添加对结果CONFIG_GPIO编译处理

如:obj-$(CONFIG_GPIO) +=gpio.o

如果懒得加这些七七八八的东西直接写这样也OK:obj-y +=gpio.o

注释:CONFIG_xxx表示一个全局变量,只是起到传递参数的作用。

在/uClinux-dist/vendors/Samsung/44B0的Makefile文件中添加设备节点:

       zero,c,1,5       random,c,1,8  urandom,c,1,9  \

       \

       gpioDev,c,126,0 \

       \

       ram0,b,1,0      ram1,b,1,1 \

 

动态加载模块到内核:

insmod与modprobe区别:

modprobe会到相应目录下找到对模块并执行insmod安装模块。

命令还有lsmod与rmmod

 

Gpio应用程序:

/********************************iotest.c****************************************/
#include 
#include 
#include "gpio.h"
 
int main(int argc,char *argv[])
{
       intfd;
       inti;
       fd= open("/dev/gpioDev",O_RDONLY);
       if(fd < 0)
       {
              printf("openerror\n");
              return0;
       }
       ioctl(fd,OUT,1);
       ioctl(fd,OUT,2);
       ioctl(fd,OUT,3);
       for(;;)
       {
              ioctl(fd,SET,3);
              ioctl(fd,CLR,2);
              ioctl(fd,CLR,1);
              sleep(1);
              ioctl(fd,SET,2);
              ioctl(fd,CLR,1);
              ioctl(fd,CLR,3);
              sleep(1); 
              ioctl(fd,SET,1);
              ioctl(fd,CLR,2);
              ioctl(fd,CLR,3);
              sleep(1);
       }
       close(fd);
       return0;
}

/******************************Makefile**************************************/

EXEC = iotest
OBJS = iotest.o
 
all: $(EXEC)
 
$(EXEC): $(OBJS)
       $(CC)$(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
 
romfs:
       $(ROMFSINST)/bin/$(EXEC)
clean:
       -rm-f $(EXEC) *.elf *.gdb *.o

添加应用程序到内核中:

a、 在/uClinux-xxx/config/目录中的config.in文件中添加配置菜单项

如:bool ‘iotest-app’ CONFIG_USER_IOTEST

b、 配置结果是保存在/uClinux-xxx/config/目录中的.config文件中,对其结果进行处理在Makefile文件在user目录下

如:dir_$( CONFIG_USER_IOTEST) += iotest // iotest为应用程序目录名称

 

注释:应用程序源代码是放在/uClinux-xxx/user目录下的

      dirà表示目录文件夹

      objà表示目标文件

 

在上面这些参数都被设置后,最终被编入到目录/uClinux-dist/vendors/Samsung/44B0/中的对应的config.xxx文件中,以使其中的Makefile进行对整个工程编译成最终的镜像文件。

你可能感兴趣的:(uClinux)