Chinaunix首页 | 论坛 | 博客
  • 博客访问: 852214
  • 博文数量: 321
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 936
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-23 11:25
文章分类

全部博文(321)

文章存档

2017年(1)

2016年(10)

2015年(61)

2014年(187)

2013年(62)

分类: 嵌入式

2013-03-04 14:28:05

/proc/devices/----设备名      /dev/-----节点名称

一、驱动程序:

驱动程序是应用层和硬件设备之间的一个软件层

它向应用层提供了一组标准化的调用接口, 同时完全隐藏设备的工作细节

二、操作系统的作用:

1、一个复杂的软件系统需要处理多个并发的任务。

2、提供内存管理机制。每个进程都独立地访问4GB的内存空间,其中0-3GB属于用 户空间,3GB-4GB属内核空间。

3、设备驱动都按照操作系统给出的独立于设备的接口而设计,应用程序将可使用统一 的系统调用接口来访问各个设备。

三、驱动的存在:

a) 编译进内核启动内核时就会驱动此硬件设备。

b) 模块方式: 编译生成一个.ko文件当应用程序需要时再动态加载进内核空间运行。

c) 用脚本来写。

字符设备是一种可以按字节以串行顺序依次访问的设备===字节流

四、Linux用户程序通过设备文件(又名:设备节点 /dev/)来使用驱动程序操作设备

网络设备任何网络事务都通过一个接口来进行一个接口通常是一个硬件设备(eth0), 但是它也可以是一个纯粹的软件设备比如回环接口(lo)。一个网络接口负责发送和接收数据报文。网络设备没有对应设备文件

五、内核编程注意事项:

a) 不能调用用户空间函数

b) 不能使用浮点数

c) 不能使用死循环

六、字符设备文件<====设备号====>字符设备驱动

七、设备当文件处理,所以有目录:/dev/===节点。一个设备可以有多个节点或者一个节点

八、节点名/dev/称最好和设备名/proc/devices一样。

加载 insmod  (insmod hello.ko)

卸载 rmmod  (rmmod hello)

查看所有已加载模块 lsmod 

查看某个模块信息 modinfo hello.ko

查看输出:

dmesg

cat /var/log/messages

ARM平台上无需查看,自动自动打印输出到屏幕

Struct file ===代表一个打开的文件,可以有多个,因为可以多次被打开

Struct inode===代表一个设备文件

Struct cdev===代表内核中的一个设备

Struct file_operations====代表设备的操作函数:应用程序和VFS(虚拟文件系统)之间的接口是系统调用。而VFS和磁盘文件系统及普通设备之间的接口是file_operations

    由于字符设备的上层没有磁盘文件系统,所以字符设备的file_operations函数由驱动提供。File_operations正是字符设备驱动的核心。

Cdev 重要成员file_operations 定义了字符设备驱动提供给虚拟文件系统的接口函数。

One

先定义一个代表这个设备类型的结构体

  struct globalmem_dev                                     

{                                                        

  struct cdev cdev; /*cdev结构体*/                       

  unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/   

 };

并定义全局的struct globalmem_dev *globalmem_devp; /*设备结构体指针*/

Two:

module_init(globalmem_init);

module_exit(globalmem_exit);

实现:

int globalmem_init(void)

{

一、申请设备号:

1、静态申请

 result = register_chrdev_region(devno, 1, "globalmem");

Devno:主次设备号;

1:申请几个;

"globalmem":设备名;/proc/devices

2、动态分配

  result = alloc_chrdev_region(&devno, 0, 1, "globalmem");

    Devno:主次设备号

     0:次设备号从0开始

 1:  1个次设备

 "globalmem":设备名;/proc/devices

     globalmem_major = MAJOR(devno);//分解出主设备号

二、动态申请设备结构体的内存

 globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);

 memset(globalmem_devp, 0, sizeof(struct globalmem_dev));

 用来存放设备文件的信息;返回设备结构体的指针。

 或者在fifo中通过它来访问。转换。

三、初始化并注册cdev

1、分配cdev

       cdev_init(&dev->cdev, &globalmem_fops);

2、初始化cdev:列出三个重要成员

  dev->cdev.owner = THIS_MODULE;

  dev->cdev.ops = &globalmem_fops;

  //dev->cdev.dev = devno;

12步是为了让内核能够识别cdev

3、添加设备到内核中

 err = cdev_add(&dev->cdev, devno, 1);//devno:主次设备号

四、创建节点:即设备文件

1、手工创建:

  mknod /dev/test c 235 0

Mknod 设备名 字符设备主设备号 次设备号

2、自动创建

a) 先创建struct class *my_class;

class-> my_class = class_create(THIS_MODULE, "my_class");

b) 创建节点: device_create( my_class, NULL, MKDEV(globalmem_major, 0),  NULL, "globalmem");

:2.6.12->devfs_mk_cdev(devno, S_IFCHR|S_IRUGO|S_IWUSR, "globalmem");

}

void globalmem_exit(void)

{

 一、注销cdev

cdev_del(&globalmem_devp->cdev);

二、删除节点:

 device_destroy(my_class, MKDEV(globalmem_major, 0)); 

三、删除class

class_destroy(my_class);   

四、释放设备结构体内存:

kfree(globalmem_devp); 

五、注销设备号:

 unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);

}

Three:

1、定义变量(文件操作结构体)

static const struct file_operations globalmem_fops =

{

  .owner = THIS_MODULE,

  .llseek = globalmem_llseek,

  .read = globalmem_read,

  .write = globalmem_write,

  .ioctl = globalmem_ioctl,

  .open = globalmem_open,

  .release = globalmem_release;

};

2、对应实现上面的函数:

a) static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)

b) static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)//ppos是指向文件的位置

c) static ssize_t globalmem_write(struct file *filp, const char __user *buf,size_t size, loff_t *ppos)

d) static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)

e) int globalmem_release(struct inode *inode, struct file *filp)

f) int globalmem_open(struct inode *inode, struct file *filp)

注意:dev->cdev.owner = THIS_MODULEowner几乎全部都是THIS_MODULE

1、模块加载函数(必需)

安装模块时被系统自动调用的函数,通过module_init宏来指定

2、模块卸载函数(必需)

 卸载模块时被系统自动调用的函数,通过module_exit宏来指定

3、许可证申明(必须)

MODULE_LICENSE被用来告知内核该模块带有一个许可证,没有这样的说明,加载模块时内核会抱怨。

4、模块参数(可选)

通过宏MODULE_PARM指定模块参数,模块参数用于在加载模块时传递参数给它。

5、模块作者(可选)

MODULE_AUTHOR(lai"); 

加载 insmod  (insmod hello.ko)

卸载 rmmod  (rmmod hello)

查看所有已加载模块 lsmod 

查看某个模块信息 modinfo hello.ko

查看输出:

dmesg

cat /var/log/messages

模块信息:在/sys/module

ARM平台上无需查看,自动自动打印输出到屏幕

linux内核中,所有标示为 _ _init的函数在连接的时候都放在.ini.text这个区段内。 

用于调试定义打印信息:

#ifdef  DEBUG

#define DPRINTK  printk

#else

#define DPRINTK( x... ) //注意:宏带可变参数是linux c 的语法。

#endif

阅读(1065) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~