linux内核按⾏读⽂件,Linux内核读写⽂件以及从SD卡读⽂件并
处理的⽅法
在Linux的应⽤平台上,很多时候我们需要⽤到从SD卡读数据来使⽤,⽐如升级触摸屏固件,⽐如载⼊调试⽂本等,都需要⽤到Linux的⽂件系统来操作。
(1)基础函数
这些函数主 要有: filp_open() filp_close(), vfs_read() vfs_write(),set_fs(),get_fs()等,这些函数在linux/fs.h和asm/uaccess.h 头⽂件中声明。
a,打开⽂件。filp_open():在kernel中可以打开⽂件,其原形如下:strcut file* filp_open(const char* filename, int open_mode, int mode);  该函数返回strcut file*结构指针,供后继函数操作使⽤,该返回值⽤IS_ERR()来检验其有效性。 filename:表明要打开或创建⽂件的名称(包括路径部分)。在内核中打开的⽂件时需要注意打开的时机,⽐如需要打开的⽂件所在设备还没有挂载到⽂件系统,会导致打开失败。open_mode:
⽂件的打开⽅式,可以取O_CREAT,O_RDWR,O_RDONLY等。 mode:⾃⼰实验时必设为0777,⽅具有完全的读写权限,否则
filp_open会返回失败。
b,读写⽂件。kernel中⽂件的读写操作可以使⽤vfs_read()和vfs_write,两函数的原形如下:ssize_t vfs_read(struct file* filp, char __user* buffer, size_t len, loff_t* pos);  ssize_t vfs_write(struct file* filp, const char __user* buffer, size_t len, loff_t* pos);  在使⽤vfs_read()和vfs_write()最后需要注意的⼀点是最后的参数loff_t
* pos,pos所指向的值要初始化,表明从⽂件的什么地⽅开始读写,⼀般设0。注意buffer是指针。
c,权限函数get_fs()和 set_fs()这两个函数。b所讲的两个函数的第⼆个参数buffer,前⾯都有__user修饰符,这就要求这两个buffer指针都应该指向⽤户空间的内存,如果对该参数传递kernel空间的指针,这两个函数都会返回失败-EFAULT。要使这两个读写函数使⽤kernel空间的buffer指针也能正确⼯作,需要使⽤set_fs()函数,其原形如下:void set_fs(mm_segment_t fs);该函数的作⽤是改变kernel对内存地址检查的处理⽅式,其实该函数的参数fs只有两个取值:USER_DS,KERNEL_DS,分别代表⽤户空间和内核空间,默认情况下,kernel取值为USER_DS,即对⽤户空间地址检查并做变换。那么要在这种对内存地址做检查变换的函数中使⽤内核
空间地址,就需要使⽤set_fs(KERNEL_DS)进⾏设置。这两个函数的⼀般⽤法为:
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
...... //与内存有关的操作
set_fs(old_fs);
还有⼀些其它的内核函数也有⽤__user修饰的参数,在kernel中需要⽤kernel空间的内存代替时,都可以使⽤类似办法。
d, 关闭读写⽂件。int filp_close(struct file*filp, fl_owner_t id);  该函数的使⽤很简单,第⼆个参数⼀般传递NULL值。
注意点:其实Linux Kernel组成员不赞成在kernel中独⽴的读写⽂件(这样做可能会影响到策略和安全问题),对内核需要操作的⽂件内容,最好由应⽤层完成。样例代码:
#include #include #include #include static char buf[] = "你好";
static char buf1[10];
linux内核文件放在哪
int __init hello_init(void) {
struct file *fp;
mm_segment_t fs;
loff_t pos;
printk("hello enter
");
fp = filp_open("/home/niutao/kernel_file", O_RDWR | O_CREAT, 0644);
if (IS_ERR(fp)) {
printk("create file error
");
return -1;
}
fs = get_fs();
set_fs(KERNEL_DS);
pos = 0;
vfs_write(fp, buf, sizeof(buf), &pos);
pos = 0;
vfs_read(fp, buf1, sizeof(buf), &pos);
printk("read: %s
", buf1);
filp_close(fp, NULL);
set_fs(fs);
return 0;
}
(2)经常会⽤到的读写⼀个⽂件作为存储标志的做法
很多时候,系统关机时需要底层⼀个⽂件保存0或者1,以备下次开机后系统直接读取之前的状态值。同时,这个标志位在系统运⾏时也是可以随时改变,并影响流程。通过sysfs来操作,注意权限,否则读写⽆效。
static DEVICE_ATTR(ftstpwakeupswitch, S_IRWXUGO | S_IRWXUGO, fts_tpwakeupswitch_show,
fts_tpwakeupswitch_store);static struct attribute *fts_attributes[] = {
...............................
&dev_attr_ftsfwupgradeapp.attr,
&dev_attr_ftstpwakeupswitch.attr,
NULL
};具体函数
u8 tpwakeupswitch = 1;//运⾏中他处需要判断的变量
static ssize_t fts_tpwakeupswitch_show(struct device *dev,struct device_attribute *attr,char *buf)
{//上层读
ssize_t num_read_chars = 0;
tpwakeupswitch_read();//会读取保存的⽂件并改变tpwakeupswitch的值
num_read_chars = snprintf(buf, PAGE_SIZE, "%d
", tpwakeupswitch);
return num_read_chars;
}
static ssize_t fts_tpwakeupswitch_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count) {//上层写
if('1' == *buf)
tpwakeupswitch = 1;
else
tpwakeupswitch = 0;
tpwakeupswitch_write();//会根据tpwakeupswitch的值写⼊到⽂件中
return count;
}读写⽂件函数如下:static int tpwakeupswitch_read()
{
char temp;
struct file *fp = NULL;
mm_segment_t fs;
loff_t pos;
if (NULL == fp)
fp = filp_open("/", O_RDWR | O_CREAT, 0777);
if (IS_ERR(fp)) {
printk("tpwakeupswitch_read create or open file error
");
return -1;
}
fs = get_fs();
set_fs(KERNEL_DS);
pos = 0;
vfs_read(fp, &temp, sizeof(temp), &pos);
if('1' == temp )
tpwakeupswitch = 1;
else
tpwakeupswitch = 0;
filp_close(fp, NULL);
set_fs(fs);
return 0;
}
static int tpwakeupswitch_write()
{
char temp;
struct file *fp = NULL;
mm_segment_t fs;
loff_t pos;
if (NULL == fp)
fp = filp_open("/", O_RDWR | O_CREAT, 0777);
if (IS_ERR(fp)) {
printk("tpwakeupswitch_write create or open file error
");
return -1;
}
fs = get_fs();
set_fs(KERNEL_DS);
pos = 0;
if(1 == tpwakeupswitch)
temp = '1';
else
temp = '0';
vfs_write(fp, &temp, sizeof(temp), &pos);
filp_close(fp, NULL);
set_fs(fs);
return 0;
}
需要注意的是,show和store通常只是操作了attr(查看或者单击checkbox)之后才会跑到,默认开机是不会跑show当然也不会去读之前保存的值作为实时变量的,那么必须在变量判断的地⽅前执⾏⼀次read操作(也即TP的suspend前),来获得关机前保存的变量值作为实时变量。
另⼀个注意的地⽅是,show和store才会创建⽂件,如果是重新格式化第⼀次开机,这个⽂件是没有的,如果没有⽂件没有初始化值(有时也客户要求初始化成某个值),会导致异常。此时在read中添加⼀个若⽂件为空则初始化某个值的过程即可。
loff_t file_size;
struct inode *inode = NULL;
....
inode = fp->f_dentry->d_inode;
file_size = inode->i_size;
if(0 == file_size )//⽂件长度为0,肯定是初建⽂件,默认写个值
{
pos = 0;
temp = '1';
vfs_write(fp, &temp, sizeof(temp), &pos);
static ssize_t melfas_fwupdate_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count) {
int UpResult;
mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM);
printk("run here
");
UpResult = ms6000_firmware_upgrade_from_TCard();//T卡升级主函数
if(UpResult== MS6000_RET_SUCCESS){
printk("MFS6000 DOWNLOAD SUCCESS
");
msleep(100);
}
else
mfs6000_print_fail_result(UpResult);
i2c_client->addr = MS6000_8BIT_I2CADDR;
mt_set_gpio_mode(GPIO_I2C0_SCA_PIN, GPIO_I2C0_SCA_PIN_M_SCL);
mt_set_gpio_mode(GPIO_I2C0_SDA_PIN, GPIO_I2C0_SDA_PIN_M_SDA);
mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);//恢复中断和I2C脚的使⽤
return count;
}
(4)从T卡读⽂件并处理(cred处理是多余的)
static int ms6000_firmware_upgrade_from_TCard()
{
unsigned char NewFwVersion,OldFwVersion;
UINT16 rdlen;//实际读⼊内存的⽂件长度

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。