- 论坛徽章:
- 0
|
2011年2月24号
开始正式的驱动程序了,早上一来就仔细了研读了一下LDD3关于字符设备的驱动程序的步骤。看了两个小时左右就有了自己的思路,在具体的展开字符驱动设备编写之前,先来说说我思路:
1. 首先在驱动中首先一个写nor flash的操作,这里我决定先写第127扇区,安全起见
2. 用户态运行一个应用程序调用驱动中的写操作来写nor flash。
那么问题就来了:
第一:用户态的write操作怎么就能解析到驱动中的write操作?
第二:用户态的数据怎么能传给内核态?
第一个问题,在这我就不详细的解释了
http://dev.firnow.com/course/6_s ... 08831/139065_2.html
大家仔细看一下上面的帖子就明白了,也就是网上流传的write的奥秘,写的蛮不错的,为了搞清楚这个流程,我还去read the f***ing linux source code了。
关于第二个问题:起始网上也有,在这里简单的介绍四个函数:
copy_to_usr()—copy a block data into user space
copy_from_users --copy a block data from user space
get_user()和put_user关于这四个函数具体的解释大家去google吧。
下面来讲解我们本帖的正式的主题,字符驱动设备的开发的步骤:
第一步:注册你的设备,由于本文是2.4的内核因此使用了register_chrdev这个函数,当然还有其他函数,可以参考LDD3的第三章,具体的注册方法如下:
dev_major=FLASH_DEV_MAJOR;
register_chrdev(dev_major, "NORFLASH", &flash_fops);
这里的dev_major是你注册的设备的主设备号:FLASH_DEV_MAJOR是我定义的一个宏:
#define FLASH_DEV_MAJOR 200,为什么我会使用200了?大家可以在自己的linux终端下输入如下的命令:ls -l /dev会发现有如下的输出:
-rwxr-xr-x 1 root root 1620 Jan 5 2011 ELDK_FIXOWNER
-rwxr-xr-x 1 root root 6252 Jan 5 2011 ELDK_MAKEDEV
crw-r--r-- 1 root root 218, 0 Jan 1 21:51 commode
crwxr-xr-x 1 root root 5, 1 Jan 2 03:27 console
lrwxrwxrwx 1 root root 3 Jan 5 2011 fb -> fb0
crwxr-xr-x 1 root root 29, 0 Jan 5 2011 fb0
lrwxrwxrwx 1 root root 7 Jan 5 2011 flash_environment -> flasha3
lrwxrwxrwx 1 root root 7 Jan 5 2011 flash_kernel -> flasha2
lrwxrwxrwx 1 root root 7 Jan 5 2011 flash_monitor -> flasha1
lrwxrwxrwx 1 root root 7 Jan 5 2011 flash_reserved -> flasha4
crwxr-xr-x 1 root root 60, 0 Jan 5 2011 flasha
crwxr-xr-x 1 root root 60, 1 Jan 5 2011 flasha1
crwxr-xr-x 1 root root 60, 2 Jan 5 2011 flasha2
crwxr-xr-x 1 root root 60, 3 Jan 5 2011 flasha3
crwxr-xr-x 1 root root 60, 4 Jan 5 2011 flasha4
crwxr-xr-x 1 root root 60, 5 Jan 5 2011 flasha5
crwxr-xr-x 1 root root 60, 6 Jan 5 2011 flasha6
crwxr-xr-x 1 root root 60, 7 Jan 5 2011 flasha7
crwxr-xr-x 1 root root 60, 8 Jan 5 2011 flashb
crwxr-xr-x 1 root root 60, 9 Jan 5 2011 flashb1
crwxr-xr-x 1 root root 60, 10 Jan 5 2011 flashb2
crwxr-xr-x 1 root root 60, 11 Jan 5 2011 flashb3
crwxr-xr-x 1 root root 60, 12 Jan 5 2011 flashb4
crwxr-xr-x 1 root root 60, 13 Jan 5 2011 flashb5
crwxr-xr-x 1 root root 60, 14 Jan 5 2011 flashb6
crwxr-xr-x 1 root root 60, 15 Jan 5 2011 flashb7
crwxr-xr-x 1 root root 1, 7 Jan 5 2011 full
brwxr-xr-x 1 root root 3, 0 Jan 5 2011 hda
brwxr-xr-x 1 root root 3, 1 Jan 5 2011 hda1
大家注意:第一列那一串英文最前面的字符有的是c,有的是b,有的是l,这里没有d,c表示是字符设备,b表示块设备,d表示是目录文件,l表示是链接文件,第4列表示设备的设备号,我发现200没有被占用,所以我就用了200,大家注意,在2.4中用这种方式,起始在2.6中已经不提倡这种方式,最好的是通过动态分配,具体的方法大家可以参考ldd3
第二步:定义驱动的方法:在ldd3中我们会看到这样的一个数据结构:
static struct file_operations 这个结构里面的每一个成员都是一个指向函数的指针,这个里面也就是填充的我们驱动对应的方法:本文中的这个数据结构的初始化如下:
static struct file_operations flash_fops =
{
.owner = THIS_MODULE,
.open = flash_open,
.release = flash_release,
.read = flash_read,
.write = flash_write,
};
这边要继续阐述一个问题:在前面我们提到当在用户态调用一个write方法写nor flash的时候,那么这个方法会通过文件系统解析到nor flash驱动的write的方法,也就是说如果用户空间发生一个write(nor flash)经过文件系统解析后会调用flash_write(nor flash)操作。
第三步:实现具体的方法:在这里详细阐述一下flash_write的方法:
static ssize_t flash_write(struct file *filep,const char *buf,size_t count,loff_t *pstroff)这是flash_write的原型,具体的每个参数的含义请参考ldd3,下面是flash_write具体的实现:
kmalloc_mem=(char *)kmalloc(count,GFP_ATOMIC);首先通过kmalloc分配内存空间,在这里我请大家去google一下以下几个分配函数的区别,我相信google之后会得到很详细的解释在这里,我就不作解释了:
kmalloc(),
vmalloc(),
get_free_page(),
__get_free_pages(),
alloc_page()
alloc_pages()
malloc()
kmap()
这几个函数在我们驱动开发中除了malloc不用,其他的都会用到的,所以请大家自己去google一下吧。
分配好内存之后将用户的数据拷贝到内核空间:
copy_from_user(kmalloc_mem,buf,count);
拷贝结束之后调用write_to_flash将数据写到nor flash中去,写nor flash的方法这里和上一篇文章在内核模块中写nor flash是一样的
write_to_flash(kmalloc_mem,count);
下面是我的用户态程序:请大家仔细的看一下open操作后面的注释:- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include<stdarg.h>
- #include <fcntl.h>
- #include <assert.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #define LEN 64
- static void printdata(char *buffer,int len);
- int main(int argc,char *argv[])
- {
-
- int i,fd;
- char buf[64];
- char *read_buf;
- for(i=0;i<LEN;i++)
- buf[i]='a';
- fd=open("/dev/NORFLASH",O_RDWR);//打开nor flash设备文件,注意这是在终端下首先通过insmod将模块插入,然后mknod命令完成设备文件的创建,这个步骤很重要
- if(fd<0)
- {
- printf("open error\n");
- return -1;
- }
- if(write(fd,buf,LEN)<0)
- {
- printf("write fail\n");
- return -1;
- }
- read_buf=(char *)malloc(LEN);
- if(read(fd,read_buf,LEN)<0)
- {
- printf("read fail\n");
- return -1;
- }
- printdata(read_buf,LEN);
- return 0;
- }
- static void printdata(char *buffer,int len)
- {
- int i;
- for(i=0;i<len;i++)
- {
- printf("[%d]=%c ",i, buffer[i]);
- if (i%8==7) printf("\n");
- }
-
- printf("\n");
- return;
- }
复制代码 下面是我的驱动程序:- #ifndef __KERNEL__
- #define __KERNEL__
- #endif
- #ifndef __MODULE__
- #define __MODULE__
- #endif
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/fs.h>
- #include <linux/proc_fs.h> // proc
- #include <linux/mm.h>
- #include <linux/wrapper.h>
- #include <linux/errno.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/vmalloc.h>
- #include <linux/time.h>
- #include <linux/interrupt.h>
- #include <asm/uaccess.h>
- #include <linux/poll.h>
- #include <asm/io.h> /*for ioremap*/
- #define FLASH_START_ADDR 0xff000000
- #define MEM_START 0xff000000 /* the first phsical address of nor flash*/
- #define MEM_SIZE 0x01000000 /* the total size of nor flash, 16M*/
- #define SECT_SIZE 0x00020000 //128K
- #define SECT_OFFSET_ADDR (127*SECT_SIZE)//第127扇区相对于FLASH_START_ADDR的偏移地址
- #define SECT_START_ADDR (SECT_OFFSET_ADDR+FLASH_START_ADDR)//第127扇区的起始地址0xffe00000
- #define FLASH_DEV_MAJOR 200
- volatile unsigned char *iomap_flash_addr;
- static int dev_major;
- char *kmalloc_mem;
- static int write_to_flash(char *buf,ssize_t len);
- static void erase_flash(void);
- static int write_to_flash(char *buf,ssize_t len)
- {
- // int left;/*bytes left */
- ssize_t i;
- unsigned short data;
- volatile unsigned char *addr_ptr;
- addr_ptr=iomap_flash_addr;
-
- // addr_ptr=iomap_flash_addr[file->f_pos];/*get the first address to write in */
-
-
- erase_flash();/*erase flash before write*/
-
- for(i=0;i<len;i++)
- {
-
- data=*buf++;
- local_irq_disable();
- *addr_ptr = 0x50;/* clear status register */
- *addr_ptr = 0x40;/* write byte */
- *addr_ptr = data;
- *addr_ptr = 0x70;/* read status register */
- while((*addr_ptr & 0x80) != 0x80 )
- {
- *addr_ptr = 0x70;
- }
-
- local_irq_enable();
- addr_ptr++;
- }
-
- *addr_ptr = 0xFF;/* reset to read mode */
- return 0;
- }
- static void erase_flash()
- {
-
- volatile unsigned char *addr;
- addr=iomap_flash_addr;
-
- printk(KERN_ALERT"start to erase:\n");
- local_irq_disable();
- *addr = 0x50; /* clear status register */
- *addr = 0x20; /* erase setup */
- *addr = 0xD0; /* erase confirm */
- *addr = 0x70; /* read status register */
- while((*addr & 0x80) != 0x80 )
- {
- *addr = 0x70;
- }
- local_irq_enable();
- printk(KERN_ALERT"erase sector ok!\n");
- *addr = 0xFF;/* reset to read mode */
- return;
- }
-
- static ssize_t flash_read(struct file *filep,
- char *buf,
- size_t count,
- loff_t *pstroff)
- {
- copy_to_user(buf,(char *)iomap_flash_addr,count);
- return count;
- }
- static ssize_t flash_write(struct file *filep,
- const char *buf,
- size_t count,
- loff_t *pstroff)
- {
-
- kmalloc_mem=(char *)kmalloc(count,GFP_ATOMIC);
- copy_from_user(kmalloc_mem,buf,count);
- write_to_flash(kmalloc_mem,count);
- return count;
- }
- static int flash_open(struct inode *inode, struct file *filep)
- {
- MOD_INC_USE_COUNT;
- return 0;
- }
- static ssize_t flash_release(struct inode *inode, struct file *filep)
- {
- MOD_DEC_USE_COUNT;
- return 0;
- }
- static struct file_operations flash_fops =
- {
- .owner = THIS_MODULE,
- .open = flash_open,
- .release = flash_release,
- .read = flash_read,
- .write = flash_write,
-
- };
- int flash_init(void)
- {
- int ret;
- dev_major=FLASH_DEV_MAJOR;
- ret = register_chrdev(dev_major, "NORFLASH", &flash_fops);
- if (ret < 0)
- {
- printk("register fail!\n");
- return ret;
- }
- if (dev_major == 0)
- {
- dev_major = ret;
- } /*random molloc device*/
- printk("flash_driver device major number %d:\n",dev_major);
- iomap_flash_addr=(volatile unsigned char *)ioremap(SECT_START_ADDR,SECT_SIZE);
- if(iomap_flash_addr==NULL)
- {
- printk(KERN_ALERT"iomap fail\n");
- unregister_chrdev(dev_major,"NORFLASH");
- return -1;
- }
- printk(KERN_ALERT"iomap_flash_addr=%p\n",iomap_flash_addr);
- return 0;
- }
- void flash_exit(void)
- {
- if(iomap_flash_addr!=NULL)
- iounmap((void*)iomap_flash_addr);
- kfree(kmalloc_mem);
- unregister_chrdev(dev_major, "NORFLASH");
- return;
- }
- module_init(flash_init);
- module_exit(flash_exit);
- MODULE_LICENSE("GPL");
- EXPORT_NO_SYMBOLS;
复制代码 上面的两个程序经过测试,发现通过用户态调用底层驱动写nor flash最后127扇区的方案是可行的,那么明天我直接准备更换nor flash中的kernel文件了,好紧张啊!嘿嘿,这两天发现学了太多太多的东西了,看了不知道多少书,不知道用了多少次google和baidu,每天都是干活干到12点多,不过发现还是蛮充实 |
评分
-
查看全部评分
|