Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9464327
  • 博文数量: 1750
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 20091
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1750)

文章存档

2024年(26)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: LINUX

2012-07-03 18:19:19

在V8项目中的测试代码 
/*
* just test for TY TBW7808
* get mac address from filesystem when wlan0 link up.
* if (read OK & valid data) [not default mac address and not 00:00:00:00:00:00]
* return this mac addr
*else
* gen GUID to support random mac addr then return it
*/

#include
#include
#include

#include
#include
#include
#include
#include
#include

#include
#include

#include
#define MY_MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MY_MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"

#define MAC_ADDR_FILE "/vendor/mac_addr.info"

/*
*  gen random seq and serialize to mac format. save it to [custom_mac]
*/
static void random_soft_mac_address(char *custom_mac, int len)
{
uuid_be uid;
memset(custom_mac, 0, len);
uuid_be_gen(&uid);
sprintf(custom_mac, MY_MACSTR, MY_MAC2STR(uid.b));

memcpy(custom_mac, "88:88:00", 8);
printk(KERN_ERR "\n\n\n\n*****************************************************\n");
printk(KERN_ERR "UUID-MAC  :["MY_MACSTR"]\n", MY_MAC2STR(uid.b));
printk(KERN_ERR "custom_mac:[%s]\n", custom_mac);
printk(KERN_ERR "\n\n\n\n*****************************************************\n");
}

static int is_valid_mac(const char *mac, int len)
{
int idx = 0;
if (len < 17) return 0;
if (mac[17] != '\0') return 0;

if ((mac[2] != ':') || (mac[5] != ':') || (mac[8] != ':') || (mac[11] != ':') || (mac[14] != ':'))
return 0;

for (idx=0; idx<6; idx++) {
if (!isxdigit(mac[idx*3+0]) || !isxdigit(mac[idx*3+1]))
return 0;
}

return 1;
}

/*
* get mac addr from rootfilesystem into custom_mac.
* return 0: get OK
* >0: the mac is random
* <0: some error
*/
int ty_read_macaddr_from_fs(char *custom_mac, int len)
{
struct file *fp      = NULL;
char buf[18]         = {0};
int iret;

if (len < 18) return -1;
memset(custom_mac, 0, len);
fp = filp_open(MAC_ADDR_FILE, O_RDONLY, 0);
if (IS_ERR(fp)) { //File not exists. so Create it and write mac addr
printk(KERN_ERR "[%s-%d] mac address file not exist.\n", __func__, __LINE__);
goto gen_random_mac;
}
else { // mac file found.
iret = kernel_read(fp, 0, buf, 18);
filp_close(fp, NULL);

buf[17] = '\0';
if (!is_valid_mac(buf, sizeof(buf)) || (strncmp(buf , "00:00:00:00:00:00" , 17) == 0)) { //invalid mac addr
printk(KERN_ERR "[%s-%d] mac address file .\n", __func__, __LINE__);
goto gen_random_mac;
}
else { //mac addr OK
memcpy(custom_mac, buf, 17);
}
}

return 0;
gen_random_mac:
random_soft_mac_address(custom_mac, len);
return 1;
}

/*
* 0: write OK.
* else : some error.
* maybe this file should be created by android framework ?
*/
/*
int ty_write_macaddr_to_fs(const char *custom_mac, int len)
{
struct file *fp      = NULL;
mm_segment_t oldfs   = {0};
if (len < 18) return -1;

fp = filp_open(MAC_ADDR_FILE, O_RDWR | O_CREAT, 0666);
if (IS_ERR(fp)) { //can't create file ?
printk(KERN_ERR "[%s-%d] can't create mac address file.\n", __func__, __LINE__);
return -1;
}
else { //create file OK.  now write mac addr to file.
oldfs = get_fs();
set_fs(get_ds());
if (fp->f_mode & FMODE_WRITE) {
ret = fp->f_op->write(fp,
(const char *)custom_mac,
len, &fp->f_pos);
if (ret < 0)
DHD_ERROR(("[WIFI] Mac address [%s] Failed to write into File.\n", custom_mac));
else
DHD_INFO(("[WIFI] Mac address [%s] written into File.\n", custom_mac));
}
set_fs(oldfs);
filp_close(fp, NULL);
}
return 0;
}
*/

内核空间读写文件的常规操作步骤同用户空间一样


  第一步:打开文件,获取文件指针

  第二步:将文件读入到一段内存中

  第三步:将一段内存中的数据写入到另一个文件中。

  完成上述功能要用的内核函数有:

  ◆打开文件filp_open()

  ◆关闭文件filp_close()

  ◆读文件内容到内存中vfs_read()

  ◆写内存中的数据到文件vfs_write()

  函数 filp_open(const char* filename, int open_mode, int mode)

  函数功能:在内核空间中打开文件

  函数原形:

  strcut file* filp_open(const char* filename, int open_mode, int mode);

  返回值:strcut file*结构指针,供后继函数操作使用,该返回值用IS_ERR()来检淘熹有效性。

  参数:

  filename:表明要打开或创建文件的名称(包罗路径部分)。

  open_mode:文件的打开方式,O_RDONLY 只读打开、O_WRONLY 只写打开、O_RDWR 读写打开、O_CREAT 文件不存在则创建。

  mode:创建文件时使用,设置创建文件的权限,其它情况可以匆略设为0

  示例

  struct file *file = NULL;

  file = filp_open(/root/test.txt,O_RDWR|O_CREAT,0);

  以读写方式(没有则创建)打开文件/root/test.txt。并返回test.txt的文件指针给file.函数 filp_close(struct file*filp, fl_owner_t id)

  函数功能:关闭之前打开文件

  函数原型:int filp_close(struct file*filp, fl_owner_t id);

  参数:

  struct file*filp:打开文件的文件指针

  fl_owner_t id:一般传递NULL值,也可用current->files作为实参。

  示例

  filp_close(file, NULL); 关闭指针为file的文件。函数 vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)

  函数功能:读取已经打开的文件到内存中

  函数原型:

  ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)

  {

  ssize_t ret;

  if (!(file->f_mode & FMODE_READ)) 判断文件是否可读

  return -EBADF;

  if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read)) 是否定义文件读方法

  return -EINVAL;

  if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))

  return -EFAULT;

  ret = rw_verify_area(READ, file, pos, count); 读校验 ,

  if (ret >= 0)

  {

  count = ret;

  if (file->f_op->read)

  ret = file->f_op->read(file, buf, count, pos); 调用文件读操作方法

  else

  ret = do_sync_read(file, buf, count, pos); 通用文件模型读方法

  if (ret > 0)

  {

  fsnotify_access(file->f_path.dentry);

  add_rchar(current, ret);

  }

  inc_syscr(current);

  }

  return ret;

  }通过filp_open我们已经可以在当前进程的文件描述表中找到了file , 于是我们就可以调用保存在file中的文件操作方法(file_operation) file->f_op->read(file, buf, count, pos)来具体的操作文件。

  上面的代码实现并不复杂,在做了一些条件判断以后,如果该文件索引节点inode定义了文件的读实现方法的话,就调用此方法。Linux下特别文件读往往是用此方法, 一些伪文件系统如:proc,sysfs等,读写文件也是用此方法。而如果没有定义此方法就会调用通用文件模型的读写方法.它最末就是读内存,或者需要从存储介质中去读数据.

  参数:

  struct file *file:打开的文件返回的文件指针,(读的目标文件)

  char __user *buf:在用户空间开辟的一段内存空间的首地址,用来保存文件数据。

  size_t count:指定读取文件中的多少内容。单位字节

  loff_t *pos:文件起始位置偏移值,若从文件头读取,则偏移值为0.可以在文件自身的信息中获取

  示例

  int *buf;

  loff_t *pos = &(file->f_pos);

  buf = (int *)kmalloc(fsize+100,GFP_KERNEL);

  分配一个文件自身大小+100字节边界的内存空间,将用来存放打开的文件[url=]笑看传奇[/url],,内存分配方式为kmalloc的flag标志GFP_KERNEL。

  vfs_read(file, buf, fsize, pos); 读文件(指针为file)到内存(buf为起始地址)中,读取字节数定为文件自身大小,偏移为自身.函数 vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)

  函数功能:将内存中的一段数据写到文件中

  函数原形:

  ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)

  {

  ssize_t ret;

  if (!(file->f_mode & FMODE_WRITE))

  return -EBADF;

  if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))

  return -EINVAL;

  if (unlikely(!access_ok(VERIFY_READ, buf, count)))

  return -EFAULT;

  ret = rw_verify_area(WRITE, file, pos, count);

  if (ret >= 0)

  {

  count = ret;

  if (file->f_op->write)

  ret = file->f_op->write(file, buf, count, pos);

  else

  ret = do_sync_write(file, buf, count, pos);

  if (ret > 0)

  {

  fsnotify_modify(file->f_path.dentry);

  add_wchar(current, ret);

  }

  inc_syscw(current);

  }

  return ret;

  }可以看出这个函数和vfs_read()是差不多的,只是调用的文件操作方法不同而已(file->f_op->write) ,如果没有定义file->f_op->write ,同样也需要do_sync_write()调用同样文件写操作, 首先把数据写到内存中,然后在适当的时候把数据同步到具体的存储介质中去.

  参数:

  struct file *file:打开的文件返回的文件指针,(写的目标文件)

  char __user *buf:数据在内存中的位置,以该地址为起始的一段内存数据将要写到文件中

  size_t count:指定写入文件中的多少内容。单位字节

  loff_t *pos:文件起始位置偏移值,若从文件头读取,则偏移值为0.可以在文件自身的信息中获取

  示例

  loff_t *pos = &(file->f_pos);

  vfs_write(file,buf,fsize,pos);获取文件的大小

  我们可以哄骗文件的inode结构获得文件的大小,参考代码如下

  struct file *file = NULL;

  struct inode *inode = NULL;

  file = filp_open(file_path,O_RDWR|O_CREAT,0);

  inode = file->f_dentry->d_inode;

  fsize = inode->i_size;

  printk(KERN_ALERT "size=%d\n",(int)fsize);示例代码

  此ko模块代码在arm架构的fpga上已经跑通。因为涉及的参数比较多,为了清楚地重现重要步骤,对每步骤的函数进行了简单的封装。参数的传递只要理解上面的介绍即可区分清楚。执行流程在static int hello_init(void)函数中

  

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #define FILE_PATH_READ "/file_read_test"

  打开文件路径(包括文件名),未来将要读的

  #define FILE_PATH_WRITE "/new_file_test"

  打开文件路径(包括文件名),未来将要写的

  struct file *file = NULL; 保存打开文件的文件指针变量

  struct inode *inode = NULL; 为了获取文件大小用的inode结构变量

  int *file_buf; 保存开辟的内存空间的地址的指针变量

  loff_t fsize; 保存文件大小的变量

  mm_segment_t old_fs; 保存内存边界的变量

  

  static int kernel_file_open(char *file_path)

  {

  file = filp_open(file_path,O_RDWR|O_CREAT,0);

  if (IS_ERR(file))

  {

  printk("Open file %s failed.\n", file_path);

  return 0;

  }

  }

  

  static loff_t kernel_file_size(struct file *file)

  {

  inode = file->f_dentry->d_inode;

  fsize = inode->i_size;

  printk(KERN_ALERT "size=%d\n",(int)fsize);

  return fsize;

  }

  

  static int kernel_addr_limit_expend(void)

  {

  old_fs = get_fs();

  set_fs(KERNEL_DS);

  return 0;

  }

  

  static int kernel_addr_limit_resume(void)

  {

  set_fs(old_fs);

  }

  

  void *kernel_file_read(struct file *file,loff_t fsize)

  {

  int *buf;

  loff_t *pos = &(file->f_pos);

  buf = (int *)kmalloc(fsize+100,GFP_KERNEL);

  vfs_read(file, buf, fsize, pos);

  return buf;

  }

  

  static int kernel_file_write(struct file *file,int *buf,loff_t fsize)

  {

  loff_t *pos = &(file->f_pos);

  vfs_write(file,buf,fsize,pos);

  }

  

  static int hello_init(void) ko的主函数

  {

  printk(KERN_ALERT "Y(^_^)Y Hello Wang`s file.\n");

  kernel_file_open(FILE_PATH_READ); 打开文件file_read_test

  kernel_file_size(file); 获取file_read_test的大小

  

  kernel_addr_limit_expend(); 边界扩展

  file_buf = kernel_file_read(file,fsize); 读操作

  filp_close(file, NULL); 关闭文件file_read_test

  kernel_addr_limit_resume(); 边界恢复

  

  kernel_file_open(FILE_PATH_WRITE); 打开文件new_file_test,没有则创建

  kernel_addr_limit_expend(); 边界扩展

  kernel_file_write(file,file_buf,fsize); 将前面读到内存中的数据,写入到文件new_file_test中

  filp_close(file, NULL); 关闭文件

  kernel_addr_limit_resume(); 边界恢复

  return 0;

  }

  static void hello_exit(void)

  {

  printk(KERN_ALERT "BYE BYE file Y(^_^)Y\n");

  }

  module_init(hello_init);

  module_exit(hello_exit);

  MODULE_LICENSE("Dual BSD/GPL");

  MODULE_AUTHOR("wby");

  MODULE_DESCRIPTION("A simple hello world Module with File");
阅读(2116) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~