当前位置: 技术问答>linux和unix
[求助]驱动中寄存器操作问题
来源: 互联网 发布时间:2016-09-27
本文导语: 刚刚接触Linux驱动,最近在做一个串口扩展芯片的驱动,现在已经可以在内核挂载驱动模块了,测试代码也可以正常进入ioctlwrite函数操作。但是无法对扩展芯片的寄存器进行操作,cpu是ARM的2440,串口扩展芯片连接8位...
刚刚接触Linux驱动,最近在做一个串口扩展芯片的驱动,现在已经可以在内核挂载驱动模块了,测试代码也可以正常进入ioctlwrite函数操作。但是无法对扩展芯片的寄存器进行操作,cpu是ARM的2440,串口扩展芯片连接8位数据总线,地址空间为BANK5。大家帮忙分析下问题,现在自己没什么思路。
//TL16C554 address map
//扩展芯片寄存器物理地址到虚拟地址映射,这个函数在模块加载_init中调用
int tl1A_AddressMap(void)
{
tl1A.vBase = (unsigned char *)ioremap_nocache(tl1A.nAddress, 8);
if(tl1A.vBase == NULL)
return -1;
tl1A.RBR = (int)(tl1A.vBase);
tl1A.THR = (int)(tl1A.vBase);
tl1A.LSR = (int)(tl1A.vBase + 5);
tl1A.MSR = (int)(tl1A.vBase + 6);
tl1A.LCR = (int)(tl1A.vBase + 3);
tl1A.FCR = (int)(tl1A.vBase + 2);
tl1A.MCR = (int)(tl1A.vBase + 4);
tl1A.DLL = (int)(tl1A.vBase);
tl1A.DLM = (int)(tl1A.vBase + 1);
tl1A.IER = (int)(tl1A.vBase + 1);
tl1A.SPR = (int)(tl1A.vBase + 7);
tl1A.IIR = (int)(tl1A.vBase + 2);
return 0;
}
//外设芯片的初始化
//TL1A初始化
void Init_TL1A(void)
{
volatile unsigned char byRx = 0;
int i = 0;
//初始化接收缓冲区指针
tl1A.sRecvHead = 0;
tl1A.sRecvTail = 0;
//FIFO控制寄存器
//设置FCR.FIFO使能,RXD复位,TXD复位,mode=1,触发为14;轮询方式触发设置无效
writeb(0xcf, tl1A.FCR);
//*(volatile unsigned char *)(tl1A.FCR) = 0xcf;
for(i=0; i 4096) //每个通道最多只能缓存16个字节
break;
}
}
//应用程序调用ioctl进行内存初始化,打印寄存器信息
static int TL1A_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case TL_INIT:
printk("IER = 0x%x n",readb(tl1A.IER));
printk("LCR = 0x%x n",readb(tl1A.LCR));
printk("DLL = 0x%x n",readb(tl1A.DLL));
printk("DLM = 0x%x n",readb(tl1A.DLM));
Init_TL1A();
printk("IER = 0x%x n",readb(tl1A.IER));
printk("LCR = 0x%x n",readb(tl1A.LCR));
printk("DLL = 0x%x n",readb(tl1A.DLL));
printk("DLM = 0x%x n",readb(tl1A.DLM));
break;
default:
return -EINVAL;
}
现在的问题就是初始化前后的寄存器和设定值不同,有个疑问:
1.自己做的板子,在内核中没有进行虚拟地址和物理地址的映射设定,程序采用动态映射,是否有影响?
2.刚接触Linux驱动,有个疑问,我现在要操作的是外部设备寄存器,采用动态地址映射是否可以?驱动读写ARM控制寄存器是正常的
初始化代码、读写代码在无OS情况下都验证过了,读写都没有问题。
自己已经调试两天了,有点焦头烂额,只好来论坛求助了~~~,大家帮帮忙
//TL16C554 address map
//扩展芯片寄存器物理地址到虚拟地址映射,这个函数在模块加载_init中调用
int tl1A_AddressMap(void)
{
tl1A.vBase = (unsigned char *)ioremap_nocache(tl1A.nAddress, 8);
if(tl1A.vBase == NULL)
return -1;
tl1A.RBR = (int)(tl1A.vBase);
tl1A.THR = (int)(tl1A.vBase);
tl1A.LSR = (int)(tl1A.vBase + 5);
tl1A.MSR = (int)(tl1A.vBase + 6);
tl1A.LCR = (int)(tl1A.vBase + 3);
tl1A.FCR = (int)(tl1A.vBase + 2);
tl1A.MCR = (int)(tl1A.vBase + 4);
tl1A.DLL = (int)(tl1A.vBase);
tl1A.DLM = (int)(tl1A.vBase + 1);
tl1A.IER = (int)(tl1A.vBase + 1);
tl1A.SPR = (int)(tl1A.vBase + 7);
tl1A.IIR = (int)(tl1A.vBase + 2);
return 0;
}
//外设芯片的初始化
//TL1A初始化
void Init_TL1A(void)
{
volatile unsigned char byRx = 0;
int i = 0;
//初始化接收缓冲区指针
tl1A.sRecvHead = 0;
tl1A.sRecvTail = 0;
//FIFO控制寄存器
//设置FCR.FIFO使能,RXD复位,TXD复位,mode=1,触发为14;轮询方式触发设置无效
writeb(0xcf, tl1A.FCR);
//*(volatile unsigned char *)(tl1A.FCR) = 0xcf;
for(i=0; i 4096) //每个通道最多只能缓存16个字节
break;
}
}
//应用程序调用ioctl进行内存初始化,打印寄存器信息
static int TL1A_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case TL_INIT:
printk("IER = 0x%x n",readb(tl1A.IER));
printk("LCR = 0x%x n",readb(tl1A.LCR));
printk("DLL = 0x%x n",readb(tl1A.DLL));
printk("DLM = 0x%x n",readb(tl1A.DLM));
Init_TL1A();
printk("IER = 0x%x n",readb(tl1A.IER));
printk("LCR = 0x%x n",readb(tl1A.LCR));
printk("DLL = 0x%x n",readb(tl1A.DLL));
printk("DLM = 0x%x n",readb(tl1A.DLM));
break;
default:
return -EINVAL;
}
现在的问题就是初始化前后的寄存器和设定值不同,有个疑问:
1.自己做的板子,在内核中没有进行虚拟地址和物理地址的映射设定,程序采用动态映射,是否有影响?
2.刚接触Linux驱动,有个疑问,我现在要操作的是外部设备寄存器,采用动态地址映射是否可以?驱动读写ARM控制寄存器是正常的
初始化代码、读写代码在无OS情况下都验证过了,读写都没有问题。
自己已经调试两天了,有点焦头烂额,只好来论坛求助了~~~,大家帮帮忙
|
1.自己做的板子,在内核中没有进行虚拟地址和物理地址的映射设定,程序采用动态映射,是否有影响?
// 我的理解,调用ioremap_nocache,就已经进行了内核虚拟地址和物理地址的映射了。在内核态直接使用内核虚拟地址就可以操作硬件了。
// 我的理解,调用ioremap_nocache,就已经进行了内核虚拟地址和物理地址的映射了。在内核态直接使用内核虚拟地址就可以操作硬件了。
|
映射的时候要将范围指定好,8个寄存器肯定不是第二个参数为8的,这肯定有问题啊
|
呵呵,在驱动力地址映射好了就可以直接操作寄存器的哦
|
遇见:
映射程序有点不规范,至少应该在映射之间先向系统请求该物理空间tl1A.nAddress,查看是否可用。
映射程序有点不规范,至少应该在映射之间先向系统请求该物理空间tl1A.nAddress,查看是否可用。