设备管理是操作系统必须完成的任务。而linux用“设备也是文件的概念”十分出色的完成了该任务。
linux下对设备进行分类,主要分为3大类,字符设备,块设备,网络设备。字符设备主要完成输入输出功能,例如鼠标设备/dev/psaux,图形界面设备/dev/fb0。块设备是硬盘,软盘等辅助存储设备,对这些设备的读取写入都以512字节或512字节的倍数操作,主要用于完成文件系统,保存需要用到的程序或数据。网络设备则用于完成网络任务。
(以下讨论字符设备与块设备,网络设备以后讨论。)
Linux使用树形结构管理设备,可以看下图。
设备分为块设备和字符设备,块设备和字符设备各自有256个主设备,主设备又可存在256个次设备,主设备表示一种设备类型,比如鼠标,键盘,而次设备可以是该种设备类型的具体体现,如鼠标又有atixl鼠标,psaux鼠标。主设备和次设备数目并未规定,不过区间在1-256之间。通过主设备号和次设备号便可以确定一个设备,近而操作它。而linux使用设备文件的概念使我们可以更简单的操作设备。linux为每个设备创建了一个特殊的文件,该文件节点中保存了设备的主设备号与次设备号,所以我们可以通过文件的名字(准确说是路径)来使用设备,而不用记住主设备号或次设备号。一般的设备文件都存储在/dev目录下。可以使用ls命令查看。
ls -l /dev
总用量 232
crw------- 1 root root 10, 10 2003-01-30 adbmouse
crw-r--r-- 1 root root 10, 175 2003-01-30 agpgart
crw------- 1 root root 10, 4 2003-01-30 amigamouse
crw------- 1 root root 10, 7 2003-01-30 amigamouse1
crw------- 1 root root 10, 134 2003-01-30 apm_bios
drwxr-xr-x 2 root root 4096 5月 31 21:10 ataraid
crw------- 1 root root 10, 5 2003-01-30 atarimouse
crw------- 1 root root 10, 3 2003-01-30 atibm
crw------- 1 root root 10, 3 2003-01-30 atimouse
crw------- 1 root root 14, 4 2003-01-30 audio
crw------- 1 root root 14, 20 2003-01-30 audio1
crw------- 1 root root 14, 7 2003-01-30 audioctl
brw-rw---- 1 root disk 29, 0 2003-01-30 aztcd
crw------- 1 root root 10, 128 2003-01-30 beep
brw-rw---- 1 root disk 41, 0 2003-01-30 bpcd
crw------- 1 root root 68, 0 2003-01-30 capi20
......
其中crw——- c表示该设备是字符设备,brw-rw—- b表示是块设备。
crw-r–r– 1 root root 10, 175 2003-01-30 agpgart中10,175表示该设备主设备号为10,次设备号为175。
树形结构不仅便于使用,更便于管理。当我们要增加设备时,只需要找到一个未使用的主设备号,添加设备驱动,并创建对应设备文件,便可以使用该设备了。
除了树形管理机制,linux更是提供机制使我们可以用使用统一的接口操作设备。linux下对设备的操作与文件操作接口完全一致。使用了open,close,read,write,lseek,mmap等来操作设备。其中,块设备与文件的概念十分接近,都可以看成是一维数组,操作使用等同的接口并不为奇。但字符设备与文件看起来确实不同,却用相同的操作方式,这正是linux的厉害之处。字符设备大都是输入输出设备,而输入是将外界事物数据化,使cpu可以处理,这与读操作对应。而输出则是将数字转化为外界事物,这对应的是一个写操作。而mmap映射则为处理图形界面提供了巨大的方便,使我们可以使用操作内存的方式操作界面。
以下是操作设备文件的两个实例。
1.获取块设备的大小
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fd;
fd=open("/dev/sda2",O_RDONLY);
if(fd==-1)
{
printf("open file wrong \n");
return;
}
off_t off=lseek(fd,0,SEEK_END);
//多少个G
long long gs=off/1024/1024/1024;
printf("size of %d %lld %lld\n",sizeof(off_t),off,gs);
return 0;
}
(注意 32位的系统下,gcc命令要执行gcc -D_FILE_OFFSET_BITS=64,不然获取的偏移最大只能是4G。详细可以见)
2.读取鼠标数据
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fd, retval;
char buf[6];
fd_set readfds;
struct timeval tv;
fd = open("/dev/psaux", O_RDONLY);
if(fd==-1)
{
printf("Failed to open \"/dev/input/mice\"\n");
return -1;
}
printf("open right \n");
while(1)
{
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
retval = select(fd+1, &readfds, NULL, NULL, NULL);
if(retval==1)
{
if(FD_ISSET(fd,&readfds))
{
if(read(fd, buf, 6) <= 0)
{
continue;
}
printf("Button type = %d X = %d Y = %d\n", (buf[0] & 0x07), buf[1], buf[2]);
}
}
}
close(fd);
return 0;
}
附录
Linux下的设备文件
Linux内核所能识别的所有设备都记录在