新書推薦:
《
鸣沙丛书·鼎革:南北议和与清帝退位
》
售價:HK$
121.0
《
从康德到黑格尔的发展:兼论宗教哲学(英国观念论名著译丛)
》
售價:HK$
60.5
《
突破不可能:用特工思维提升领导力
》
售價:HK$
77.3
《
王阳明大传:知行合一的心学智慧(精装典藏版)
》
售價:HK$
221.8
《
失衡与重塑——百年变局下的中国与世界经济
》
售價:HK$
132.2
《
南方谈话:邓小平在1992
》
售價:HK$
80.6
《
纷纭万端 : 近代中国的思想与社会
》
售價:HK$
109.8
《
中国古代文体形态研究(第四版)(中华当代学术著作辑要)
》
售價:HK$
168.0
|
編輯推薦: |
全面解析基于ARM内核的嵌入式Linux驱动开发,通过丰富的实战案例让单片机开发者熟练掌握嵌入式Linux驱动开发。
|
內容簡介: |
随着半导体技术和芯片技术的飞速发展,能运行嵌入式 Linux系统的 MPU 芯片价格也在不断降低,ARM 架构 的芯片在手机、工业控制、物联网、自动驾驶等领域得到了广泛应用。以前大量使用 MCU 的地方也开始使用嵌入式 Linux地系铁统刷。卡的闸机、汽车充电桩的操作面板、物联网网关等都有嵌入式 Linux的身影,各企业对嵌入式 Linux开发 人才的需求也急剧增加。相比单片机开发,嵌入式 Linux开发难度要大很多。尤其是最重要的驱动开发,嵌入式 Linux内核采用面向对象思路设计,且已开发大量驱动框架,开发人员需要掌握这些驱动框架的使用,编写出符合嵌 入式 Linux要求的驱动。 本书从最基本的点灯程序到网络驱动的编写,涵盖了 Linux开发的三大驱动类型:字符设备驱动、块设备驱动 和网络设备驱动。本书的一大特色就是涵盖了全设备树开发,除了最开始的几个为了讲解嵌入式 Linux如何操作 芯片寄存器的例程没有采用设备树外,其他的例程都采用设备树,基本涵盖了嵌入式 Linux驱 动 开 发 中 的 常 用 外设。本书可作为广大从事嵌入式开发、物联网、工业控制开发等工程技术人员的学习和参考用书,也可作为高等学 校计算机、电子、自动化等专业嵌入式系统、微机接口、物联网等课程的教材。
|
關於作者: |
左忠凯,14年参加工作以来一直从事于嵌入式教育,以第一作者身份著有《FreeRTOS源码详解与应用开发》,参与编写了正点原子大量的手把手教你STM32系列书籍,比如《精通STM32F4库函数版》、《STM32F7原理与应用》等。同时录制了大量的STM32相关教学视频,广受好评。18年开始负责公司Linux教育平台的研发,编写了1800多页的Linux驱动开发教程,录制了200多讲Linux开发视频,负责的I.MX6ULL开发板自从发布至今,销量一直处于淘宝第一,Linux驱动开发相关视频在各大平台的点击量超过30万次。
|
目錄:
|
第四篇ARM Linux驱动开发篇
第1章字符设备驱动开发
1.1字符设备驱动简介
1.2字符设备驱动开发步骤
1.2.1驱动模块的加载和卸载
1.2.2字符设备注册与注销
1.2.3实现设备的具体操作函数
1.2.4添加LICENSE和作者信息
1.3Linux设备号
1.3.1设备号的组成
1.3.2设备号的分配
1.4chrdevbase字符设备驱动开发实验
1.4.1实验程序编写
1.4.2编写测试App
1.4.3编译驱动程序和测试App
1.4.4运行测试
第2章嵌入式Linux LED灯驱动开发实验
2.1Linux下LED灯驱动原理
2.1.1地址映射
2.1.2I/O内存访问函数
2.2硬件原理图分析
2.3实验程序编写
2.3.1LED灯驱动程序编写
2.3.2编写测试App
2.4运行测试
2.4.1编译驱动程序和测试App
2.4.2运行测试
第3章新字符设备驱动实验
3.1新字符设备驱动原理
3.1.1分配和释放设备号
3.1.2新的字符设备注册方法
3.2自动创建设备节点
3.2.1mdev机制
3.2.2创建和删除类
3.2.3创建设备
3.2.4参考示例
3.3设置文件私有数据
3.4硬件原理图分析
3.5实验程序编写
3.5.1LED灯驱动程序编写
3.5.2编写测试App
3.6运行测试
3.6.1编译驱动程序和测试App
3.6.2运行测试
第4章Linux设备树
4.1什么是设备树
4.2DTS、DTB和DTC
4.3DTS语法
4.3.1.dtsi头文件
4.3.2设备节点
4.3.3标准属性
4.3.4根节点compatible属性
4.3.5向节点追加或修改内容
4.4创建小型模板设备树
4.5设备树在系统中的体现
4.6特殊节点
4.6.1aliases子节点
4.6.2chosen子节点
4.7Linux内核解析DTB文件
4.8绑定信息文档
4.9设备树常用OF操作函数
4.9.1查找节点的OF函数
4.9.2查找父/子节点的OF函数
4.9.3提取属性值的OF函数
4.9.4其他常用的OF函数
第5章设备树下的LED灯驱动实验
5.1设备树LED驱动原理
5.2硬件原理图分析
5.3实验程序编写
5.3.1修改设备树文件
5.3.2LED灯驱动程序编写
5.3.3编写测试App
5.4运行测试
5.4.1编译驱动程序和测试App
5.4.2运行测试
第6章pinctrl和gpio子系统实验
6.1pinctrl子系统
6.1.1pinctrl子系统简介
6.1.2I.MX6ULL的pinctrl子系统驱动
6.1.3设备树中添加pinctrl节点模板
6.2gpio子系统
6.2.1gpio子系统简介
6.2.2I.MX6ULL的gpio子系统驱动
6.2.3gpio子系统API函数
6.2.4设备树中添加gpio节点模板
6.2.5与GPIO相关的OF函数
6.3硬件原理图分析
6.4实验程序编写
6.4.1修改设备树文件
6.4.2LED灯驱动程序编写
6.4.3编写测试App
6.5运行测试
6.5.1编译驱动程序和测试App
6.5.2运行测试
第7章Linux蜂鸣器实验
7.1蜂鸣器驱动原理
7.2硬件原理图分析
7.3实验程序编写
7.3.1修改设备树文件
7.3.2蜂鸣器驱动程序编写
7.3.3编写测试App
7.4运行测试
7.4.1编译驱动程序和测试App
7.4.2运行测试
第8章Linux并发与竞争
8.1并发与竞争
8.2原子操作
8.2.1原子操作简介
8.2.2原子整型数据操作API函数
8.2.3原子位操作API函数
8.3自旋锁
8.3.1自旋锁简介
8.3.2自旋锁API函数
8.3.3其他类型的锁
8.3.4自旋锁使用注意事项
8.4信号量
8.4.1信号量简介
8.4.2信号量API函数
8.5互斥体
8.5.1互斥体简介
8.5.2互斥体API函数
第9章Linux并发与竞争实验
9.1原子操作实验
9.1.1实验程序编写
9.1.2运行测试
9.2自旋锁实验
9.2.1实验程序编写
9.2.2运行测试
9.3信号量实验
9.3.1实验程序编写
9.3.2运行测试
9.4互斥体实验
9.4.1实验程序编写
9.4.2运行测试
第10章Linux按键输入实验
10.1Linux下按键驱动原理
10.2硬件原理图分析
10.3实验程序编写
10.3.1修改设备树文件
10.3.2按键驱动程序编写
10.3.3编写测试App
10.4运行测试
10.4.1编译驱动程序和测试App
10.4.2运行测试
第11章Linux内核定时器实验
11.1Linux时间管理和内核定时器简介
11.1.1内核时间管理简介
11.1.2内核定时器简介
11.1.3Linux内核短延时函数
11.2硬件原理图分析
11.3实验程序编写
11.3.1修改设备树文件
11.3.2定时器驱动程序编写
11.3.3编写测试App
11.4运行测试
11.4.1编译驱动程序和测试App
11.4.2运行测试
第12章Linux中断实验
12.1Linux中断简介
12.1.1Linux中断API函数
12.1.2上半部与下半部
12.1.3设备树中断信息节点
12.1.4获取中断号
12.2硬件原理图分析
12.3实验程序编写
12.3.1修改设备树文件
12.3.2按键中断驱动程序编写
12.3.3编写测试App
12.4运行测试
12.4.1编译驱动程序和测试App
12.4.2运行测试
第13章Linux阻塞和非阻塞I/O实验
13.1阻塞和非阻塞I/O
13.1.1阻塞和非阻塞简介
13.1.2等待队列
13.1.3轮询
13.1.4Linux驱动下的poll操作函数
13.2阻塞I/O实验
13.2.1硬件原理图分析
13.2.2实验程序编写
13.2.3运行测试
13.3非阻塞I/O实验
13.3.1硬件原理图分析
13.3.2实验程序编写
13.3.3运行测试
第14章异步通知实验
14.1异步通知
14.1.1异步通知简介
14.1.2驱动中的信号处理
14.1.3应用程序对异步通知的处理
14.2硬件原理图分析
14.3实验程序编写
14.3.1修改设备树文件
14.3.2程序编写
14.3.3编写测试App
14.4运行测试
14.4.1编译驱动程序和测试App
14.4.2运行测试
第15章platform设备驱动实验
15.1Linux驱动的分离与分层
15.1.1驱动的分隔与分离
15.1.2驱动的分层
15.2platform平台驱动模型简介
15.2.1platform总线
15.2.2platform驱动
15.2.3platform设备
15.3硬件原理图分析
15.4实验程序编写
15.4.1platform设备与驱动程序编写
15.4.2编写测试App
15.5运行测试
15.5.1编译驱动程序和测试App
15.5.2运行测试
第16章设备树下的platform驱动编写
16.1设备树下的platform驱动简介
16.2硬件原理图分析
16.3实验程序编写
16.3.1修改设备树文件
16.3.2platform驱动程序编写
16.3.3编写测试App
16.4运行测试
16.4.1编译驱动程序和测试App
16.4.2运行测试
第17章Linux自带的LED灯驱动实验
17.1Linux内核自带LED灯驱动使能
17.2Linux内核自带LED灯驱动简介
17.2.1LED灯驱动框架分析
17.2.2module_platform_driver()函数简介
17.2.3gpio_led_probe()函数简介
17.3设备树节点编写
17.4运行测试
第18章Linux MISC驱动实验
18.1MISC设备驱动简介
18.2硬件原理图分析
18.3实验程序编写
18.3.1修改设备树
18.3.2beep驱动程序编写
18.3.3编写测试App
18.4运行测试
18.4.1编译驱动程序和测试App
18.4.2运行测试
第19章Linux input子系统实验
19.1input子系统
19.1.1input子系统简介
19.1.2input驱动编写流程
19.1.3input_event结构体
19.2硬件原理图分析
19.3实验程序编写
19.3.1修改设备树文件
19.3.2按键input驱动程序编写
19.3.3编写测试App
19.4运行测试
19.4.1编译驱动程序和测试App
19.4.2运行测试
19.5Linux自带按键驱动程序的使用
19.5.1自带按键驱动程序源码简介
19.5.2自带按键驱动程序的使用
第20章Linux PWM驱动实验
20.1PWM驱动简介
20.1.1设备树下的PWM控制器节点
20.1.2PWM子系统
20.1.3PWM驱动源码分析
20.2PWM驱动编写
20.2.1修改设备树
20.2.2使能PWM驱动
20.3PWM驱动测试
第21章Linux LCD驱动实验
21.1Linux下LCD驱动简介
21.1.1Framebuffer设备
21.1.2LCD驱动简介
21.2硬件原理图分析
21.3LCD驱动程序编写
21.3.1修改设备树
21.3.2LCD屏幕背光节点信息
21.4运行测试
21.4.1LCD屏幕基本测试
21.4.2设置LCD作为终端控制台
21.4.3LCD背光调节
21.4.4LCD自动关闭解决方法
第22章Linux RTC驱动实验
22.1Linux内核RTC驱动简介
22.2I.MX6U内部RTC驱动分析
22.3RTC时间查看与设置
第23章Linux I2C驱动实验
23.1Linux I2C驱动框架简介
23.1.1I2C总线驱动
23.1.2I2C设备驱动
23.1.3I2C设备和驱动匹配过程
23.2I.MX6U的I2C适配器驱动分析
23.3I2C设备驱动编写流程
23.3.1I2C设备信息描述
23.3.2I2C设备数据收发处理流程
23.4硬件原理图分析
23.5实验程序编写
23.5.1修改设备树
23.5.2AP3216C驱动编写
23.5.3编写测试App
23.6运行测试
23.6.1编译驱动程序和测试App
23.6.2运行测试
第24章Linux SPI驱动实验
24.1Linux下SPI驱动框架简介
24.1.1SPI主机驱动
24.1.2SPI设备驱动
24.1.3SPI设备和驱动匹配过程
24.2I.MX6U SPI主机驱动分析
24.3SPI设备驱动编写流程
24.3.1SPI设备信息描述
24.3.2SPI设备数据收发处理流程
24.4硬件原理图分析
24.5实验程序编写
24.5.1修改设备树
24.5.2编写ICM20608驱动
24.5.3编写测试App
24.6运行测试
24.6.1编译驱动程序和测试App
24.6.2运行测试
第25章Linux RS232/485/GPS驱动实验
25.1Linux下UART驱动框架
25.2I.MX6U UART驱动分析
25.3硬件原理图分析
25.4RS232驱动编写
25.5移植minicom
25.6RS232驱动测试
25.6.1RS232连接设置
25.6.2minicom设置
25.6.3RS232收发测试
25.7RS485测试
25.7.1RS485连接设置
25.7.2RS485收发测试
25.8GPS测试
25.8.1GPS连接设置
25.8.2GPS数据接收测试
第26章Linux 多点电容触摸屏实验
26.1Linux下电容触摸屏驱动框架简介
26.1.1多点触摸协议详解
26.1.2Type A触摸点信息上报时序
26.1.3Type B触摸点信息上报时序
26.1.4MT其他事件的使用
26.1.5多点触摸使用的API函数
26.1.6多点电容触摸屏驱动框架
26.2硬件原理图分析
26.3实验程序编写
26.3.1修改设备树
26.3.2编写多点电容触摸屏驱动
26.4运行测试
26.4.1编译驱动程序
26.4.2运行测试
26.4.3将驱动添加到内核中
26.5tslib移植与使用
26.5.1tslib移植
26.5.2tslib测试
26.6使用内核自带的驱动
第27章RGB转HDMI实验
27.1RGB转HMDI简介
27.2硬件原理图分析
27.3实验驱动编写
27.3.1修改设备树
27.3.2使能内核自带的sii902x驱动
27.3.3修改sii902x驱动
27.4RGB转HDMI测试
第28章Linux音频驱动实验
28.1音频接口简介
28.1.1为何需要音频编解码芯片
28.1.2WM8960简介
28.1.3I2S总线接口
28.1.4I.MX6ULL SAI简介
28.2硬件原理图分析
28.3音频驱动使能
28.3.1修改设备树
28.3.2使能内核的WM8960驱动
28.4alsalib和alsautils移植
28.4.1alsalib移植
28.4.2alsautils移植
28.5声卡设置与测试
28.5.1amixer的使用方法
28.5.2音乐播放测试
28.5.3MIC录音测试
28.5.4Line_in录音测试
28.6开机自动配置声卡
28.7alsamixer简介
第29章Linux CAN驱动实验
29.1CAN协议简介
29.1.1何为CAN
29.1.2CAN电气属性
29.1.3CAN协议
29.1.4CAN速率
29.1.5I.MX6ULL FlexCAN简介
29.2硬件原理图分析
29.3实验程序编写
29.3.1修改设备树
29.3.2使能Linux内核自带的FlexCAN驱动
29.4FlexCAN测试
29.4.1检查CAN网卡设备是否存在
29.4.2移植iproute2
29.4.3移植canutils工具
29.4.4CAN通信测试
第30章Linux USB驱动实验
30.1USB接口简介
30.1.1什么是USB
30.1.2USB电气特性
30.1.3USB拓扑结构
30.1.4什么是USB OTG
30.1.5I.MX6ULL USB接口简介
30.2硬件原理图分析
30.2.1USB HUB原理图分析
30.2.2USB OTG原理图分析
30.3USB协议简介
30.3.1USB描述符
30.3.3USB数据包类型
30.3.4USB传输类型
30.3.5USB枚举
30.4Linux内核自带HOST实验
30.4.1USB鼠标键盘测试
30.4.2U盘实验
30.5Linux内核自带USB OTG实验
30.5.1修改设备树
30.5.2OTG主机实验
30.5.3OTG从机实验
第31章regmap API实验
31.1regmap API简介
31.1.1什么是regmap
31.1.2regmap驱动框架
31.1.3regmap操作函数
31.1.4regmap_config掩码设置
31.2实验程序编写
31.3运行测试
第32章Linux IIO驱动实验
32.1IIO子系统简介
32.1.1iio_dev
32.1.2iio_info
32.1.3iio_chan_spec
32.2IIO驱动框架创建
32.2.1基础驱动框架建立
32.2.2IIO设备申请与初始化
32.3实验程序编写
32.3.1使能内核IIO相关配置
32.3.2ICM20608的IIO驱动框架搭建
32.3.3完善icm20608_read_raw()函数
32.3.4完善icm20608_write_raw()函数
32.4测试应用程序编写
32.4.1Linux文件流读取
32.4.2编写测试App
32.4.3运行测试
第33章Linux ADC驱动实验
33.1ADC简介
33.2ADC驱动源码简介
33.2.1设备树下的ADC节点
33.2.2ADC驱动源码分析
33.3硬件原理图分析
33.4ADC驱动编写
33.4.1修改设备树
33.4.2使能ADC驱动
33.4.3编写测试App
33.5运行测试
33.5.1编译驱动程序和测试App
33.5.2运行测试
第34章Linux 块设备驱动实验
34.1什么是块设备
34.2块设备驱动框架
34.2.1block_device结构体
34.2.2gendisk结构体
34.2.3block_device_operations结构体
34.2.4块设备I/O请求过程
34.3使用请求队列实验
34.3.1实验程序编写
34.3.2运行测试
34.4不使用请求队列实验
34.4.1实验程序编写
34.4.2运行测试
第35章Linux 网络驱动实验
35.1嵌入式网络简介
35.1.1嵌入式下的网络硬件接口
35.1.2MII/RMII接口
35.1.3MDIO接口
35.1.4RJ45接口
35.1.5I.MX6ULL ENET接口简介
35.2PHY芯片详解
35.2.1PHY基础知识简介
35.2.2LAN8720A详解
35.3Linux内核网络驱动框架
35.3.1net_device结构体
35.3.2net_device_ops结构体
35.3.3sk_buff结构体
35.3.4网络NAPI处理机制
35.4I.MX6ULL网络驱动简介
35.4.1I.MX6ULL网络外设设备树
35.4.2I.MX6ULL网络驱动源码简介
35.4.3fec_netdev_ops操作集
35.4.4Linux内核PHY子系统与MDIO总线简介
35.5网络驱动实验测试
35.5.1LAN8720 PHY驱动测试
35.5.2通用PHY驱动测试
35.5.3DHCP功能配置
第36章Linux WiFi驱动实验
36.1WiFi驱动添加与编译
36.1.1向Linux内核添加WiFi驱动
36.1.2配置Linux内核
36.1.3编译WiFi驱动
36.1.4驱动加载测试
36.2wireless tools工具移植与测试
36.2.1wireless tools移植
36.2.2wireless tools工具测试
36.3wpa_supplicant移植
36.3.1openssl移植
36.3.2libnl库移植
36.3.3wpa_supplicant移植
36.4WiFi联网测试
36.4.1RTL8188 USB WiFi联网测试
36.4.2RTL8189 SDIO WiFi联网测试
第37章Linux 4G通信实验
37.14G网络连接简介
37.2高新兴ME3630 4G模块实验
37.2.1ME3630 4G模块简介
37.2.2ME3630 4G模块驱动修改
37.2.3ME3630 4G模块ppp联网测试
37.2.4ME3630 4G模块ECM联网测试
37.2.5ME3630 4G模块GNSS定位测试
37.3EC20 4G模块实验
37.3.1EC20 4G模块简介
37.3.2EC20 4G模块驱动修改
37.3.3quectelCM移植
37.3.4EC20上网测试
|
內容試閱:
|
本书和清华大学出版社已出版的《原子嵌入式 Linux驱动开发详解》是一套书籍,在《原子嵌入式 Linux驱动开发详解》这本书的前3篇中,详细讲解了ARM裸机开发、Uboot、Linux内核和根文件系统的移植,为我们学习嵌入式Linux驱动开发打下了坚实的基础。本书是第四篇——ARM Linux驱动开发篇,专门讲解嵌入式Linux驱动开发,涵盖了Linux开发的三大驱动类型: 字符设备驱动、块设备驱动、网络设备驱动。本书使用的Linux内核版本为4.1.15,其支持设备树(Device tree),所以本篇所有例程均采用设备树开发。
嵌入式Linux学习的难点在于:
(1) 基础要求高
嵌入式Linux对于学习者的基础要求比较高,需要从事过或学习过32位ARM单片机的开发。掌握32位微控制器架构的基础知识,了解32位微控制器的寄存器操作方法,掌握常用的通信协议,比如串口、I2C、SPI、RGB屏幕、SAI、网络等。零基础学习嵌入式Linux驱动开发难度很大,笔者不建议直接上手。就跟我们上学一样: 小学—初中—高中—大学,是一个循序渐进的过程。不可能小学、初中都不上,等到了年龄以后直接上高中,一次性把小学、初中和高中的知识全学了,这个难度是很大的。
(2) 驱动框架多
嵌入式Linux为了兼容众多的芯片,开发了大量的驱动框架,我们要根据这些驱动框架来编写驱动。比如一个简单的LED灯驱动程序,单片机用十几行代码就可以实现,但是在嵌入式Linux环境下可能就要几十行了。而且不同的外设,驱动框架不同,如I2C、SPI、按键输入等。嵌入式Linux驱动学习的一大内容就是学习掌握大量的驱动框架。
(3) C语言基础要求高
嵌入式Linux内核采用C语言开发,在内核中充斥着大量的C语言高级用法,像指针、结构体这种都是很常见的。C语言基础薄弱的同学上手难度也很大,所以要加强和巩固C语言的基础知识。
(4) 设备树开发方式
嵌入式Linux内核早就采用设备树进行驱动开发了,和单片机直接编写C文件开发驱动相比,设备树的引入无疑又增加了学习难度,毕竟要多学习一门技术。设备树贯穿于整个嵌入式Linux驱动开发始终,是必须熟练掌握的技术。
本书采用循序渐进、由浅入深的方式进行章节编排,先是字符设备,再是块设备,最后是网络设备。
(1) 字符设备驱动
字符设备是Linux驱动开发中最杂、最多的一类设备,小到LED点灯,大到USB、音频都属于字符设备驱动。在实际的工作中,大部分工作都是处理字符设备驱动。本书首先从一个虚拟的字符设备驱动开始,讲解字符设备基础驱动框架的使用。然后再慢慢引入设备树、GPIO、输入输出子系统、I2C、SPI等其他框架。
(2) 块设备驱动
采用内存模拟一个物理存储设备的方式,重点讲解块设备框架的使用,编写一个采用内存模拟的块设备驱动。
(3) 网络设备驱动
在实际的项目开发中,网络设备驱动也是很重要的一点,比如我们更换网络PHY以后如何调试网络驱动。本书花了大量篇幅来详细讲解嵌入式Linux的网络设备开发流程,从PHY芯片到网络驱动架构,尤其是PHY芯片的讲解。因为在真正做项目的时候,打交道的就是PHY芯片,主控端的驱动是不需要修改的,我们要做的就是驱动起来所选择的PHY芯片,让网络正常工作。
(4) 全设备树开发方式
基本上所有的例程都采用设备树的开发方式,从基本的GPIO到网络驱动。每个例程都有详细的设备树讲解,真正让读者深入掌握设备树原理。
嵌入式Linux的驱动开发学习是需要不断练习的,尤其是相比单片机开发,引入了很多复杂的知识体系。比如搭建驱动框架和设备树,很多初学者第一遍学习的感觉就是稀里糊涂的,这是因为练习得少,对这些新知识还不熟悉,这是很正常的。笔者在学习嵌入式Linux驱动开发的时候,学习了好几遍才有感觉。这里可以教大家一个方法,先用一个开发板跟着教程学习一遍,比如使用正点原子的I.MX6UL开发板。当学完了以后,再换另外一个型号的开发板,比如STM32MP157、RV1126等,将自己学过的东西在新的开发板上实践,这样就能巩固好已有的知识。
最后,祝愿大家学习顺利。
作者2023年5月
|
|