一.前言:
开发环境:CentOS6.7(虚拟机);
开发板fl2440使用的Linux版本3.0最小内核;
编写驱动原则:只提供机制,不实现功能;
Linux内核将设备按照访问特性分为三类:字符设备、块设备、网络设备;
字符设备(本次学习目标)
一个字符设备是一种可以当做一个字节流来存取的设备(如同一个文件),对于这些设备它一次I/O只访问一个字节。一个字符驱动负责实现这种行为,这样的驱动常常至少实现open,close,read,和write系统调用。
例如:本例程使用命令mknod 创建的led节点如下:
/drivers >: ls /dev/led*
/dev/led0 /dev/led1 /dev/led2 /dev/led3
注:mknod命令使用法则,可以通过mknod --help查看
块设备
常见的块设备有磁盘、光盘、U盘、SD卡、Nandflash、Norflash等。一个块设备一次I/O通常访问一个块的大小数据,这个大小通常2的幂次方字节(Nnadflash使用2048个字节)。对于块设备的使用,需要分区格式化后建立文件系统,之后在应用程序空间中使用mount命令挂载起来后使用。
网络设备
网络设备包括有线网卡(eth0)、无线网卡(wlan0)、回环设备(lo0)、拨号网络设备(ppp0)等,他们在Linux内核里由网络协议栈实现,在/dev路径下并没有相应的设备节点,通过ifconfig -a命令可以查看所有网络设备。在应用程序编程时,所有对网络设备的访问都是通过socket()来访问的。
二.字符设备驱动(注意要点)
1.主次设备号
字符设备通过文件系统中的设备名来存取,惯例上它们位于/dev目录。我们可以通过ls -l /dev 来查看当前有多少字符设备(由于有很多就不列举出来);也可以直接查看当前正在使用的cat /proc/devices;
/drivers >: ls -l /dev/led*
crwxr-xr-x 1 root root 250, 0 Jan 1 00:01 /dev/led0
crwxr-xr-x 1 root root 250, 1 Jan 1 00:01 /dev/led1
crwxr-xr-x 1 root root 250, 2 Jan 1 00:01 /dev/led2
crwxr-xr-x 1 root root 250, 3 Jan 1 00:01 /dev/led3
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
....
开头c表示字符设备,d表示文件夹,b表示块设备,s表示网络设备;
250, 0:表示主次设备号;
在编写底层驱动时,我们可以获取其主次设备号;
MAJOR(dev_t dev);
MINOR(dev_t dev);
设定主、次设备号有2种方法:1.静态设定 2.动态设定;
注:1.静态设定时要注意防止与其它设备住次设备号冲突;
2.由于主次设备号是系统资源,故一定要在程序退出时释放其对应的设备号;
2.file_operation结构
file_operation就是把系统调用和驱动程序关联起来的关键数据结构。也就是说我们平常的open,read,ioctl,close等函数的使用与其密切相关;以下是部分file_operation说明:(头文件:/usr/include/linux/fs.h)
例如:led_fops包涵open,close,ioctl调用
/* file operations open, close and ioctl */
static struct file_operations led_fops =
{
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.unlocked_ioctl = led_ioctl,
};
open函数:
static int led_open(struct inode *inode,struct file *file)
{
int minor = iminor(inode);
file->private_data = (void *)minor;
printk(KERN_DEBUG "/dev/drv_led %d opened.\n",minor);
return 0;
}
3.inode结构
当我们在Linux中创建一个文件时,就会在相应的文件系统中创建一个inode与之对应,文件实体和文件的inode是一一对应的,创建好一个inode会存在存储器中。
当我们使用mknod创建一个设备文件时,也会在文件系统中创建一个inode,这个inode和其他的inode一样,用来存储关于这个文件的静态信息,包括这个设备文件对应的设备号,文件的路径以及对应的驱动对象等。(头文件:/usr/include/linux/fs.h)
可以查看2.的例子程序,会用到inode关联;
4.file结构
linux内核会为每一个进程维护一个文件描述符表,这给表其实就是struct file的索引。open()的过程其实就是根据传入的路径填充好一个file结构并将其赋值到数组中并返回其索引。下面是file的主要内容,他一样是定义在include/linuxfs.h文件中;
可以查看2.的例子程序,会用到file关联;
5.cdev结构体
内核在内部适用类型struct cdev的结构代表字符设备。在内核调用你的设备操作前,你必须分配一个这样的结构体并注册给Linux内核,在这个结构体里对于这个设备进行操作的函数,具体定义在file_operation结构体中。
例如:
static struct cdev *led_cdev;
static int __init s3c_led_init(void)
{
led_cdev->owner = THIS_MODULE;
cdev_init(led_cdev,&led_fops);
cdev_add(led_cdev,devno,dev_count);
}
注:cdev结构体还可以以动态方式初始化;也要记得释放cdev结构体;