linux驱动学习--串口相关---知识汇总

linux驱动学习–串口相关—知识汇总

一.驱动的框架


//串口驱动模块的创建函数---------------------------------------------
static int __init uart_init_module(void)
{
    //1.字符设备的设备号部分
    register_chrdev_region();
        或者
    alloc_chrdev_region();    
    //2.注册平台设备和平台驱动
        platform_device_register_simple();//平台设备
        platform_driver_register();//平台驱动
    //3.a初始化cdev的函数,b把cdev加入内核
    //4.驱动类和驱动设备类的创建
        class_create();
        class_device_create();

}
//驱动模块的删除
static void __exit uart_exit_module(void)
{

//注销平台驱动
platform_driver_unregister(&uart_plat_driver);
//注销平台设备
platform_device_unregister(uart_platform_device);


//注销设备类
class_device_destroy(mydev_class, devno);
//注销驱动类
class_destroy(mydev_class);
//删除内核注册的cdev
cdev_del(&my_uart_devices.cdev);


//注销平台设备编号
unregister_chrdev_region(devno,1);  
}

二.相关知识

1.物理地址到虚拟地址的映射函数
void *ioremap(unsigned long phys_addr, unsigned long size);
//访问物理内存phys_addr和这段内存区的大小,返回物理地址对应的虚拟地址

void ioumap(void *addr);//这里的addr是虚拟地址

为了便于不同mcu移植,对虚拟地址中的数据操作,可以用下面的函数

unsigned int ioread32(void *addr)//从内存读取数据,返回指定地址的值
void iowrite32(unsigned int value,void *addr)//往指定内存写入数据

__iomem是linux2.6.9内核中加入的特性。是用来个表示指针是指向一个I/O的内存空间。

__force表示所定义的变量类型是可以做强制类型转换

attribute____关键字主要是用来,在函数或数据声明中设置其属性

#define S3C2410_ADDR(x)   ((void __iomem __force *)0xF0000000 + (x))
//指向I/O内存的(__iomem) 
//强制类型转换(__force)
# define __force __attribute__((force))

//---------------------------------------------------------------
//在map.h中定义了虚拟地址和物理地址
#define S3C2410_ADDR(x)    (0xF0000000 + (x))//虚拟址
//对应关系memory controller registers
#define S3C24XX_VA_MEMCTRL S3C2410_ADDR(0x00100000)
#define S3C2400_PA_MEMCTRL (0x14000000)
#define S3C2410_PA_MEMCTRL (0x48000000)
#define S3C24XX_SZ_MEMCTRL SZ_1M
#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)

__builtin_expect((x),1) 表示 x 的值为真的可能性更大;

__builtin_expect((x),0) 表示 x 的值为假的可能性更大。

__builtin_expect()期望 exp 表达式的值等于常量 c ,从而 GCC 为你优化程序,将符合这个条件的分支放在合适的地方,先执行其它。

2.加锁
spin_lock_irqsave(&port->lock, flags);
//代码不被多个cpu进程访问
//代码不被中断打断(加锁)
spin_unlock_irqrestore(&port->lock, flags);
3.圆(环形)缓存区

□□□□□□□□□
________|

好比两个人围着一张圆形的桌子在追逐,跑的人被网络IO线程所控制,当写入数据时,这个人就往前跑;追的人就是逻辑线程,会一直往前追直到追上跑的人。如果追上了怎么办?那就是没有数据可读了,先等会儿呗

head头指针项目插入点—write
tail尾指针寻找的下一个点—read
size常量值
2n大小为2n
//返回buffer中没有读的count
#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
//返回还有几个空间可以写
#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
//假定size =8,head=6,tail=4.
//tail-(head+1) = -3 ,计算机中是用补码来表示的。-3的补码是1111 1101 & 0000 0111 = 0000 0101 =5表示还有5个空间可以写.0/1/2/3/7刚好等于5个空间.(-1的补码是1111 1111)
#define CIRC_CNT_TO_END(head,tail,size)//这将返回可以从缓冲区中提取的连续项的数量,而不必返回到缓冲区的开始位置。
#define CIRC_SPACE_TO_END(head,tail,size)//这将返回缓冲区中剩余的连续空间量,可以立即插入项目,而无需返回到缓冲区的开始位置

当尾指针等于头指针时,缓冲区是空的; 并且当头指针比尾指针少一个时,缓冲区已满。 添加项目时头部索引增加,删除项目时尾部索引增加。 尾部索引不应该跳转头部索引,并且两个索引在到达缓冲区末尾时都应该包装为0,从而允许无限量的数据流过缓冲区。

head=6 tail=4head=4 tail=6
CIRC_CNT26
CIRC_SPACE51
CIRC_SPACE_TO_END22
CIRC_CNT_TO_END21
size=23图例size=23
[–][–][–][–][a↓][ b ][ ↓ ][ –][ c ][ d ][ e ][ f ][ ↓ ][ –][a↓][ b ]
图例序号_0 _1 _2 _3 _4 _5 _6 _7_ 0 _ 1 _ 2 _ 3 _ 4 _ 5 _ 6 _7
缓冲区作用,如串口通讯-9600波特率,每3ms要传送位,传送字节要24ms传完,搬送字节进FSUB时间不能大于3ms,处理数据放入缓区
4.Makefile相关
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)

“2>” 代表重定向操作错误提示信息。只有这两个字符并不能删除错误输出。

文件文件描述符
输入文件—标准输入0(缺省是键盘,为0时是文件或其他命令的输出)
输出文件—标准输出1(缺省是屏幕,为1时是文件)
错误输出文件—标准错误2(缺省是屏幕,为2时是文件)
/dev/null看作"黑洞".写入内容都永远丢失
/dev/zero伪文件, 实际产生连续null流(二进制零)
5.cdev初始化

一个 cdev 一般它有两种定义初始化方式:静态的和动态的。
静态内存定义初始化:

struct cdev cdev;
cdev_init(&cdev, &fops);
cdev.owner=THIS_MODULE;

动态内存定义初始化:

struct cdev *cdev
cdev = cdev_alloc();
cdev->ops = &fops;
cdev->owner=THIS_MODULE;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值