Chinaunix首页 | 论坛 | 博客
  • 博客访问: 411975
  • 博文数量: 59
  • 博客积分: 1510
  • 博客等级: 上尉
  • 技术积分: 857
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-03 11:50
文章分类

全部博文(59)

文章存档

2011年(1)

2010年(36)

2009年(22)

我的朋友

分类: LINUX

2009-06-24 17:01:05

作者:ARM混迹江湖
[摘自]http://blog.tianya.cn/blogger/post_show.asp?BlogID=648077&PostID=9434859
Linux下所有的设备都是以文件的形式来操作的。设备软件分为两部分:应用程序和驱动程序,其中,应用程序负责打开设备并对它发出读写指令,驱动程序接受指令并完成读写的过程。
本文以AD5310用于AP/BG为例,讲述其应用和驱动的编写过程。
1. 硬件电路


 其中GPIO为CPU管脚,当J2上有Power Meter接上时,BNC_EN为低,程序开始从系统中获取RSSI,换算成相应的值以SPI时序送给AD5310,AD5310把它转化为相应电压,在Power Meter上显示。
2. 驱动实现
 2.1 代码编写
 驱动的编写主要是编写操作函数,例如读写等,因此驱动程序的结构比较单一,其主要的不同是操作函数的实现过程。
AD5310驱动的实现代码即说明如下:
#ifndef __KERNEL__ //判断驱动是编译进内核还是编译成模块
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif

#include … //包含相关头文件
#ifndef __MOD_INC_USE_COUNT
#define AH_MOD_INC_USE_COUNT(_m) \
 if (!try_module_get(_m)) { \
 printk(KERN_WARNING "try_module_get failed\n"); \
 return NULL; \
 }
#define AH_MOD_DEC_USE_COUNT(_m) module_put(_m)
#else
#define AH_MOD_INC_USE_COUNT(_m) MOD_INC_USE_COUNT
#define AH_MOD_DEC_USE_COUNT(_m) MOD_DEC_USE_COUNT
#endif
… //此处声明函数
struct file_operations spi_fops= //告诉系统应用程序的某个命令由谁来执行
{ //file_operation 是系统定义的结构体
 .owner = THIS_MODULE,
 .open = AD5310_open,
 .release = AD5310_release,
 .write = AD5310_write,
 .read = AD5310_read,
};
char spi_name[]="AD5310"; //device name
static int gmajor = 254; //device ID
/*************************************/
static int __init spidrv_init_module(void) //register device
{
int retv; //register_chrdev()是linux系统注册函数
 retv=register_chrdev(gmajor,spi_name,&spi_fops);
 if(retv<0)
 {
 printk("Register Fail!\n");
 return retv;
 }
 printk("SPI device OK!\n");
 return 0;
}

static void __exit spidrv_cleanup(void) //unregister device
{
 int retv;
 retv=unregister_chrdev(gmajor,spi_name);
 if(retv<0)
 {
 printk("UnRegister Fail!\n");
 return;
 }
 printk("SPIDRV:GOOD-bye!\n");
}

static int AD5310_open(struct inode *inode,struct file *file)
{ //打开文件时设置操作标记
 AH_MOD_INC_USE_COUNT(THIS_MODULE);
 return 0;
}

static int AD5310_release(struct inode *inode,struct file *file)
{
 AH_MOD_DEC_USE_COUNT(THIS_MODULE);
 return 0;
}
/*******************************************************************
 *function:init GPIO
 *description:GPIO7 use for DAC input,GPIO9 use for CS,GPIO12 use as
 *input,GPIO14 use as clock source
 *******************************************************************/
 void GPIO_init(void)
{
*IXP4XX_GPIO_GPOER = *IXP4XX_GPIO_GPOER & 0xBD7F;//GPIO7,GPIO9,GPIO14 ,output
}
/*************************************
 *read data from input GPIO12
 *************************************/
static ssize_t AD5310_read(struct file *fp, char __user *buf, size_t len, loff_t *loff)
{
 int input;
 printk("read the status of GPIO12\n");
 *IXP4XX_GPIO_GPOER = *IXP4XX_GPIO_GPOER | 0x1000;//GPIO12,input
 Delay(5);
 input = *IXP4XX_GPIO_GPINR; //get the status of GPIO12 pin
 input = input >> 12;
 input = input & 0x01;
 *buf = input;
 return(1);
}
/*********************************************************************
 *write data to output GPIO9
 *AD5310 input register contents:
 * DB15(MSB) ........................DB0(LSB)
 * x x PD1 PD0 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 x x
 *
 *PD1 PD0 = 0 0 normal operation
 *PD1 PD0 = 0 1 1K resister to GND power down modes
 *PD1 PD0 = 1 0 100K to GND power down modes
 *PD1 PD0 = 1 1 Three-State power down modes
 ********************************************************************/
static int AD5310_write(struct file *fp,char *buf,int len,loff_t *loff)
{
 int i;
 int temp;
 int spibuf;
 char *p;
 int writedata;

 p=buf; //get the data ,buf[1] low buf[0] high
 writedata=*p;
 p++;
 writedata = (writedata << 8) + *p;
 if(writedata > 1023 || writedata < 0)
{
printk("Err:the data must be 0~1023");
return -1;
}
 spibuf=0xC003; //set AD5310 operation mode as normal operation
 temp=writedata;
 temp= temp << 2;
 spibuf += temp; //the data packet needed to send to AD5310
 GPIO_init();
 Delay(100);
 *IXP4XX_GPIO_GPOUTR=*IXP4XX_GPIO_GPOUTR & 0xFDFF;//set GPIO9 low
 *IXP4XX_GPIO_GPOUTR=*IXP4XX_GPIO_GPOUTR | 0x4000;//set GPIO14 high
 for(i=0;i<16;i++) //start to send the data
{
*IXP4XX_GPIO_GPOUTR=*IXP4XX_GPIO_GPOUTR | 0x4000;//set GPIO14 high
 if ((spibuf & 0x8000) == 0)
 {
*IXP4XX_GPIO_GPOUTR=*IXP4XX_GPIO_GPOUTR & 0xFF7F; //GPIO7 output 0
}
else
 {
*IXP4XX_GPIO_GPOUTR=*IXP4XX_GPIO_GPOUTR | 0x80; //GPIO7 output 1
}
spibuf = spibuf <<1;
*IXP4XX_GPIO_GPOUTR=*IXP4XX_GPIO_GPOUTR & 0xBFFF; //set GPIO14 low
}
 *IXP4XX_GPIO_GPOUTR=*IXP4XX_GPIO_GPOUTR | 0x200;//set GPIO9 high
 *IXP4XX_GPIO_GPOUTR=*IXP4XX_GPIO_GPOUTR | 0x4000;//set GPIO14 high
 return 2;
}

/**************************************************************/
module_init(spidrv_init_module);
module_exit(spidrv_cleanup);

/*end of spidrv.c*/
 2.2 驱动编译
 在linux2.6内核下,驱动须编译成 .ko 的形式,即需要两个编译阶段,第一步生成 .o 文件,第二步生成 .ko 文件
 AD5310驱动的Makefile编写如下:
PWD := $(shell pwd) //指向当前目录
TOPDIR=$(PWD)/../
Tool := $(TOPDIR)/tools/buildroot/build_armeb/bin/ //交叉编译工具的路径
KERNELDIR=$(TOPDIR)/src/kernels/linux-2.6.13.2/ //系统内核路径
EXTRA_CFLAGS += -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -Wall//环境变量
ARC :=arm //CPU类型(平台类型)
CROSS_CC :=$(Tool)armeb-linux- //gcc名称
obj-m += spidrv.o //目标文件的源文件

default: //默认执行的命令及参量
 make ARCH=$(ARC) CROSS_COMPILE=$(CROSS_CC) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
clean: //执行清除命令时清除的文件类型
 rm -rf *.o *.ko *mod.c

2.3 驱动加载
 把生成的 .ko 文件放到板子上的某个路径下如/lib/modules,执行如下命令:
 #insmod /lib/modules/spidrv.ko > /dev/null
 #mknod /dev/AD5310 c 254 1
此时若驱动正常工作,就会输出打印信息 SPI device OK! ,并且在/dev 目录下可以看到 AD5310 这个设备。
3. 应用实现
Linux下应用程序以文件的形式来操作设备,其最基本的操作顺序为
Open() -> read()/write() -> close()
RSSI应用实现的代码如下:
#define __KERNEL__
#include … //包含需要的头文件
#define … //定义相关变量
/*******************************************************************
 *get the RSSI value
 *******************************************************************/
int GetRSSIvalue(void)
 {
 int8_t rssivalue;
 const char *ifname;
 char aa[5] = {"ath0"};
 ifname = aa;
 u_char buf[24*1024];
 struct iwreq iwr;
 u_char *cp;
 int s, len;
 s = socket(AF_INET, SOCK_DGRAM, 0);
 if (s < 0)
 err(1, "socket(SOCK_DRAGM)");
 memset(&iwr, 0, sizeof(iwr));
 strncpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name));

 iwr.u.data.pointer = (void *) buf;
 iwr.u.data.length = sizeof(buf);
 if (ioctl(s, IEEE80211_IOCTL_STA_INFO, &iwr) < 0)
 errx(1, "unable to get station information");
 len = iwr.u.data.length;
 if (len < sizeof(struct ieee80211req_sta_info))
 return;

 cp = buf;
 do {
 struct ieee80211req_sta_info *si;
 u_char *vp;
 si = (struct ieee80211req_sta_info *) cp;
 vp = (u_int8_t *)(si+1);
 rssivalue = si->isi_rssi;
 cp += si->isi_len, len -= si->isi_len;
 } while (len >= sizeof(struct ieee80211req_sta_info));
 return(rssivalue);
}
/*******************************************************************
 *main function
 *******************************************************************/
int main(int argc,char **argv)
{
 int rssivalue;
 int senddata;
 int RSSIprecision;
 char inputstate[2];
 char databuf[2];
 const int maxrssi=66;
 const int minrssi=2;
 int fd;
 int size;
if((fd=open("/dev/AD5310",O_RDWR))==-1) //打开设备文件
{
 perror("device open fail\n");
 exit(1)
}
 RSSIprecision=1023/maxrssi;
 Delay(5);
 while(1)
 {
 size = read(fd,inputstate,1,0); //读取GPIO12状态,查看是否有Meter接入
 if(inputstate[0]==1) //no meter,high
 {
 printf("RSSI not enabled!\n");
 printf("Please mount RSSI meter!\n");
 Delay(1000);
 }
 else //有Meter接入
 {
 printf("mount RSSI meter OK!");
 rssivalue = GetRSSIvalue(); //从系统中获得RSSI的值
 printf("RSSI:%4d",rssivalue);
 if(rssivalue > maxrssi)
 { //over load,display max vcc
 senddata = 1023;
 }
 else if(rssivalue <= minrssi)
 {
 senddata = 2; // output is too low
 }
 else
 {
 senddata = RSSIprecision *rssivalue; //calculate the data needed to send
 }
 databuf[1]=senddata;
 databuf[0]= senddata >> 8;
 write(fd,databuf,2,0); //把数据发送给AD5310
 printf("databuf[1]=%d\n",databuf[1]);
 printf("databuf[0]=%d\n",databuf[0]);
 sleep(1); //延时
 }
 }
}
/**************************************************************/
/*end of RSSI_AD5310*/

另外,在编写真正的应用程序之前,为了保证驱动程序的正确性,一般会先写一些小的测试应用程序来测试驱动,在驱动正确的情况下才会编写测试我们需要的应用程序。

阅读(2654) | 评论(0) | 转发(0) |
0

上一篇:Ahdemo Mode

下一篇:struct net_device 详解2

给主人留下些什么吧!~~