虹口门户网站建设,江门网站建设外包,万网网站模板购买,五个网站目录
#x1f345;点击这里查看所有博文 随着自己工作的进行#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了#xff0c;只有经常会用到的东西才有可能真正记…目录
点击这里查看所有博文 随着自己工作的进行接触到的技术栈也越来越多。给我一个很直观的感受就是某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有一点用处的技巧用的不多的技巧可能一个星期就忘了。 想了很久想通过一些手段把这些事情记录下来。也尝试过在书上记笔记这也只是一时的书不在手边的时候那些笔记就和没记一样不是很方便。 很多时候我们遇到了问题一般情况下都是选择在搜索引擎检索相关内容这样来的也更快一点除非真的找不到才会去选择翻书。后来就想到了写博客博客作为自己的一个笔记平台倒是挺合适的。随时可以查阅不用随身携带。 同时由于写博客是对外的既然是对外的就不能随便写任何人都可以看到。经验对于我来说那就只是经验而已公布出来说不一定我的一些经验可以帮助到其他的人。遇到和我相同问题时可以少走一些弯路。 既然决定了要写博客那就只能认真去写。不管写的好不好尽力就行。千里之行始于足下一步一个脚印慢慢来 写的多了慢慢也会变好的。权当是记录自己的成长的一个过程等到以后再往回看时就会发现自己以前原来这么菜。 本系列博客所述资料均来自互联网资料并不是本人原创只有博客是自己写的。出于热心本人将自己的所学笔记整理并推出相对应的使用教程方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力没有为自己谋取私利的想法。若出现侵权现象请告知本人本人会立即停止更新并删除相应的文章和代码。
设备分类 Linux系统中的设备可以分为字符设备、块设备和网络设备这三类。
字符设备 字符设备是能够像字节流一样被访问的设备通常不支持随机存取。当对字符设备发出读写请求相应的IO操作立即发生。 Linux系统中很多设备都是字符设备我们常用的键盘、串口、I2C、SPI、音频都是字符设备。 在嵌入式Linux开发中接触最多的就是字符设备以及驱动。
块设备 块设备是Linux系统中进行IO操作时必须以块为单位进行访问的设备应用程序可以寻址磁盘上的任何位置并由此读取数据随机读取。 块设备驱动会利用一块系统内存作为缓冲区因此对块设备发出读写访问并不一定立即产生硬件I/O操作。 块设备能够安装文件系统Linux系统中常见的块设备有硬盘、EMMC、NAND、SD 卡、闪存等
网络设备 网络设备既可以是网卡这样的硬件设备也可以是一个纯软件设备如回环设备。 网络设备由Linux的网络子系统驱动负责数据包的发送和接收而不是面向流设备因此在Linux系统文件系统中网络设备没有节点。 对网络设备的访问是通过socket调用产生而不是普通的文件操作如open/closc和read/write等。
其他 一个设备可以 属于多种设备驱动类型比如 USB WIFI其使用 USB 接口所以属于字符设备。但是其又能上网所以也属于网络设备驱动。 这些设备中有些设备是对实际存在的物理硬件的抽象而有些设备则是内核自身提供的功能不依赖于特定的物理硬件又称为虚拟设备。
/dev/loop[x]/dev/random/dev/null/dev/zero/dev/full
内核结构 linux内核结构如下图所示Linux的设备经由内核统一管理。 其中字符设备和块设备最终都挂载与文件子系统之下。两者都可通过虚拟文件系统找到对应的节设备点并支持使用文件接口进行访问。 设备号 linux中设备号是用来标记一类设备以及区分这类设备中具体个体的一组号码。 Linux提供了一个名为dev_t的数据类型表示设备号dev_t定义在文件include/linux/types.h里面定义如下
typedef __u32 __kernel_dev_t;
typedef __kernel_dev_t dev_t;
//include/uapi/asm-generic/int-ll64.h
typedef unsigned int __u32;dev_t其实就是unsigned int类型是一个32位的数据类型。主设备号高12位用来标记设备的类型次设备号低20位用来区分在这类设备中具体的个体设备。不同的主设备号之间次设备号编码可以出现重复现象。 因此Linux系统中主设备号范围为0~4095所以大家在选择主设备号的时候一定不要超过这个范围。 内核为了保证在主次设备号位宽发生变化时现在的程序依然可以工作内核提供了如下的几个宏编写设备驱动代码是最好使用宏来计算dev_t参数而不要使用常数去计算。
include /linux/kdev_t.h
#define MINORBITS 20
#define MINORMASK ((1U MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) MINORMASK))
#define MKDEV(ma,mi) (((ma) MINORBITS) | (mi))设备管理 前面说到主设备号高12位的范围为0~4095。不代表Linux内核可以同时管理这么多主设备。 linux内核为了方便管理设备在fs/char_dev.c中维护了一个char_device_struct结构的结构体。
/*fs/char_dev.c*/
static struct char_device_struct {struct char_device_struct *next;unsigned int major;unsigned int baseminor;int minorct;char name[64];struct cdev *cdev; /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];/* fs.h */
#define CHRDEV_MAJOR_HASH_SIZE 255内核代码中chrdevs结构体的每一个成员都是一个以char_device_struct结构体指针为元素的单项链的头指针。 每条链表中的所有元素拥有相同的主设备号及该链表所在chrdevs数组的下标。 从上面可以得知结构体的长度为255。内核通过对255取模(major%255)来实现将0~4095个主设备号分配到255个哈希表项上。 需要注意的是只有255个哈希表不代表说内核最多只有255个主设备。很多人都会陷入误区认为最多只有255个主设备这是错误的。 举个栗子设备号256与设备号1处于同一表项位置但是它们并不冲突。也就是说设备号1和设备号256是可以同时存在的。
rootubuntu:# cat /proc/devices
Character devices:1 mem4 /dev/vc/0
.......
254 gpiochip
256 hello_register_chrdev字符设备注册 Linux内核中字符设备号的分配有两个函数分别是手动分配register_chrdev_region还有自动分配alloc_chrdev_region。
register_chrdev_region 此函数用于静态注册设备号该函数第一个参数from表示是一个设备号第二个参数count是连续设备编号的个数代表当前驱动所管理的同类设备的个数第三个参数name表示设备或者驱动的名称。
/*** register_chrdev_region() - register a range of device numbers* from: the first in the desired range of device numbers; must include* the major number.* count: the number of consecutive device numbers required* name: the name of the device or driver.** Return value is zero on success, a negative error code on failure.*/
int register_chrdev_region(dev_t from, unsigned count, const char *name)优点是可以在注册的时候就知道其设备号缺点是可能会与系统中已经注册的设备号冲突导致注册失败。
示例 下方示例中注册了主设备为256的字符设备。
static int major 256;
static int minor 0;
static dev_t register_devno;
static int hello_register_chrdev(void)
{int result;printk(hello_register_chrdev \n);register_devno MKDEV(major, minor);result register_chrdev_region(register_devno, 1, hello_register_chrdev);if (result 0){printk(register_chrdev_region fail \n);return result;}return result;
}结果 驱动模块挂载后可看到256号主设备被成功注册且设备名与预期一致。
rootubuntu:# cat /proc/devices
Character devices:1 mem4 /dev/vc/0
.......
254 gpiochip
256 hello_register_chrdevalloc_chrdev_region 该函数的第一个参数*dev是返回的设备号第二个参数baseminor是次设备号起始号第三个参数count是连续设备编号的个数第四个参数name表示设备或者驱动的名称。
/*** alloc_chrdev_region() - register a range of char device numbers* dev: output parameter for first assigned number* baseminor: first of the requested range of minor numbers* count: the number of minor numbers required* name: the name of the associated device or driver** Allocates a range of char device numbers. The major number will be* chosen dynamically, and returned (along with the first minor number)* in dev. Returns zero or a negative error code.*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)该函数是由系统协助动态分配设备号分配的主设备号的范围在1-254之间系统会从chrdevs数组尾部也就是第254项依次往前找未使用的主设备号。 /* temporary */if (major 0) {for (i ARRAY_SIZE(chrdevs)-1; i 0; i--) {if (chrdevs[i] NULL)break;}if (i 0) {ret -EBUSY;goto out;}major i;}示例 使用自动分配注册一个字符设备。
static dev_t alloc_devno;
static int hello_alloc_chrdev(void)
{int result;printk(hello_alloc_chrdev \n);result alloc_chrdev_region(alloc_devno, 0, 1, hello_alloc_chrdev);if (result 0){printk(alloc_chrdev_region fail \n);return result;}return result;
}结果 驱动模块挂载后可看到名字为hello_alloc_chrdev的字符设备被成功注册设备号为243为自动分配。
rootubuntu:# cat /proc/devices
226 drm
243 hello_alloc_chrdev
244 hidraw
245 aux
246 bsg字符设备释放 设备号作为一种系统资源当所对应的设备驱动程序被卸载时就应该把设备号归还给系统以便分配给其他内核模块使用。无论是静态分配还是动态分配都是通过调用unregister_chrdev_region函数释放设备号。
/*** unregister_chrdev_region() - return a range of device numbers* from: the first in the range of numbers to unregister* count: the number of device numbers to unregister** This function will unregister a range of count device numbers,* starting with from. The caller should normally be the one who* allocated those numbers in the first place...*/
void unregister_chrdev_region(dev_t from, unsigned count)函数在chrdevs数组中查找参数from和count所对应的struct char_device_struct 对象节点找到以后将其从链表中删除并释放该节点所占用的内存从而将对应的设备号释放以供其他设备驱动模块使用。
示例 销毁前方示例创建的两个字符设备。
static void hello_exit(void)
{printk(hello_exit \n);unregister_chrdev_region(register_devno, 1);unregister_chrdev_region(alloc_devno, 1);
}结果 可以看到主设备编号为256和243的设备全部被释放。
rootubuntu:# cat /proc/devices
226 drm
244 hidraw
245 aux
246 bsg
247 hmm_device
248 watchdog
249 rtc
250 dax
251 dimmctl
252 ndctl
253 tpm
254 gpiochip那么本篇博客就到此结束了这里只是记录了一些我个人的学习笔记其中存在大量我自己的理解。文中所述不一定是完全正确的可能有的地方我自己也理解错了。如果有些错的地方欢迎大家批评指正。如有问题直接在对应的博客评论区指出即可不需要私聊我。我们交流的内容留下来也有助于其他人查看说不一定也有其他人遇到了同样的问题呢。