请教大家一个Linux下PCI卡驱动程序的问题,希望有牛人解答!

strategist 2006-02-16 09:59:10
前段时间小弟我针对Linux2.4.20-8内核写了一个PCI数据奇偶校验卡的驱动程序,驱动程序是采用模块化方法设计的,其中涉及到硬件中断处理。
虽然功能比较简单,但还是出现了一个问题:这个驱动模块第一次加载和第一次卸载都工作正常,没有什么问题,也完成了校验的功能。但是第二次加载时就会出现死机的情况。
请教各位大侠和牛人,这是怎么回事?希望大家能给小弟一个提示。
先谢谢大家了
...全文
216 点赞 收藏 8
写回复
8 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
strategist 2006-02-21
即使将 free_irq()的位置提到void __exit cleanup_module(void)里面,问题还是一样的啊
回复
float_sky 2006-02-21
可以看出,你对free_irq的用法搞错了

调用free_irq的位置是在最后一次关闭设备、硬件被告知不要再使用中断处理器之后。
回复
tb01412 2006-02-17
你要把代码贴出来,人家才能帮你,多半是一些中断共享的问题之类
回复
strategist 2006-02-17
这应该算是linux编程部分比较有意思的一块了,希望有人可以和我探讨一下这个方面的问题。
回复
strategist 2006-02-17
代码的注释行都是乱码,是因为从linux下面转过来的缘故。
希望大家看得清楚。
初次设计驱动编程,自己感觉写的比较烂,希望牛人能及时给予问题的解答。
回复
strategist 2006-02-17
以下是驱动程序代码:
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#define _NO_VERSION_
#if CONFIG_MODVERSIONS ==1
#define MODVERSIONS
#include<linux/modversions.h>
#endif
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include<linux/config.h>
#include<linux/types.h>
#include <linux/fs.h>
#include <linux/sched.h> //for request_irq()
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/io.h> //for virt_to_phys()
#include <errno.h>
#ifndef CONFIG_PCI
#define CONFIG_PCI
#endif
#include <linux/pci.h>

MODULE_LICENSE("GPL");

/*棰勫畾涔夋墍闇€鍙橀噺*/
#define jmk_VendorID 0x1172
#define jmk_DeviceID 0x0004
unsigned int jmk_major=0;
struct pci_dev *jmkdev=NULL;
const char* devname="jmkdev";

/*瀹氫箟鍗″彲鐢ㄨ祫婧愬尯鍩?/
unsigned long base0start=0,base0len=0;
unsigned long base1start=0,base1len=0;
unsigned long base2start=0,base2len=0;
unsigned long offset=0,step=0;
unsigned long i=0;//娴嬭瘯鐢ㄤ綔璁℃暟
void *iomembase0=NULL;
void *iomembase1=NULL;

/***********for global use**************/
u8 **x;
u8 *p;
u8 *q;
u8 *r;
u8 *s;
u32 addr1;
u32 addr2;
u32 addr3;
u32 addr4;
unsigned long addri=0;

void test();
static ssize_t jmk_read(struct file *file,char *buf, size_t count, loff_t *offset)
{

}

static ssize_t jmk_write(struct file *file, const char *buf, size_t count, loff_t *offset)
{
return count;
}
static int jmk_open(struct inode *inode,struct file *file )
{
MOD_INC_USE_COUNT;
return 0;
}

// 鍦?.4涓涓€涓繑鍥炲€煎彂鐜板姞瀵嗗崱
static int jmk_release(struct inode *inode, struct file *file)
{
MOD_DEC_USE_COUNT;
return 0;
}
static struct file_operations jmk_fops =
{
open: jmk_open,
read: jmk_read,
write: jmk_write,
release: jmk_release,
owner: THIS_MODULE,
};
/*****************interupting****************/
static void demo_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
disable_irq(11);
printk("interrupt now!\n");
addri=readl(iomembase1+0x0);
printk("dspp the data1 is 0x%x!\n",addri);
/****free irq***/
free_irq(11,jmkdev);
printk("free irq!\n");
enable_irq(11);
printk("please go to back!\n");
}
//鍙戠幇鍗?
//**********************************************
/*涓绘ā鍧楀紑濮?56*/
int __init init_module(void)
{
int result;
u8 val8;
unsigned long endsrc=0;

result = register_chrdev(0,devname,&jmk_fops);
if(result<0)
{
printk("jmk : can't get major number");
return result;
}
if(jmk_major==0)
{
jmk_major=result;
printk("jmk major number is %d!\n",jmk_major);
}


/*寮€濮嬫煡鎵惧崱*/
jmkdev=pci_find_device(jmk_VendorID,jmk_DeviceID,NULL);
if(!jmkdev)
{
printk("no kard!\n");
return -1;
}
else
{
printk("found card!\n");
}
/*鍚敤鍗?/
pci_enable_device(jmkdev);


/*鏌ユ壘鍗¤祫婧?/
/*base 0*/
base0start=pci_resource_start(jmkdev,0);
endsrc=pci_resource_end(jmkdev,0);
base0len=endsrc-base0start;
printk("base 0 addr is 0x%x,len is 0x%x!\n",base0start,base0len);
/*base 1*/
base1start=pci_resource_start(jmkdev,1);
endsrc=pci_resource_end(jmkdev,1);
base1len=endsrc-base1start;
printk("base 1 addr is 0x%x,len is 0x%x!\n",base1start,base1len);
/*base 2*/
base2start=pci_resource_start(jmkdev,2);
endsrc=pci_resource_end(jmkdev,2);
base2len=endsrc-base2start;
printk("base 2 addr is 0x%x,len is 0x%x!\n",base2start,base2len);

pci_read_config_byte(jmkdev,60,&val8);
printk("Interrupt Line num is 0x%x\n",val8);



if(request_irq(11,demo_interrupt,SA_SHIRQ,devname,jmkdev)==0)
{
printk("Interrupt request is ok!\n");
}
else
{
printk("irq>15 or handler==NULL or device is busy!\n");
}

/****** for the data test**********/
test();

return 0;
}
void test()
{


int i;
p=kmalloc(32,GFP_KERNEL);
if(p==NULL)
{
printk("no page1!");
}
else
{
x=&p;
addr1=(u32)(*x);

for(i=0;i<32;i++)
{
*(p+i)=0x04;
}
printk("the address1 is %x \n",addr1);
}

q=kmalloc(32,GFP_KERNEL);
if(q==NULL)
{
printk("no page2!");
}
else
{
x=&q;
addr2=(u32)(*x);

for(i=0;i<32;i++)
{
*(q+i)=0x32;
}
printk("the address2 is %x \n",addr2);
}

r=kmalloc(32,GFP_KERNEL);
if(r==NULL)
{
printk("no page3!");
}
else
{
x=&r;
addr3=(u32)(*x);
for(i=0;i<32;i++)
{
*(r+i)=0x00;
}
printk("the address3 is %x \n",addr3);
}
s=kmalloc(32,GFP_KERNEL);
if(s==NULL)
{
printk("no page4!");
}
else
{
x=&s;
addr4=(u32)(*x);
printk("the address4 is %x \n",addr4);
}


/*鐢宠浣跨敤io鍐呭瓨*/
request_mem_region(base0start,base0len,"jmkdev");
request_mem_region(base1start,base1len,"jmkdev");
/*鏄犲皠io鍐呭瓨*/
iomembase0=ioremap(base0start,base0len);
if(iomembase0==NULL)
{
printk("can't get iomem!\n");
}
else
{
printk("get iomem0 addr is 0x%x!\n",iomembase0);
}
iomembase1=ioremap(base1start,base1len);
if(iomembase1==NULL)
{
printk("can't get iomem!\n");
}
else
{
printk("get iomem1 addr is 0x%x!\n",iomembase1);
}

/*娴嬭瘯鑾峰彇鏁版嵁base0*/
addr1=virt_to_phys(p);
addri=addr1;
writel(addri,iomembase0+0x0);
addri=readl(iomembase0+0x0);
printk("dspp the data A is 0x%x!\n",addri);
addr2=virt_to_phys(q);
addri=addr2;
writel(addri,iomembase0+0x4);
addri=readl(iomembase0+0x4);
printk("dspp the data B is 0x%x!\n",addri);
addr3=virt_to_phys(r);
addri=addr3;
writel(addri,iomembase0+0x8);
addri=readl(iomembase0+0x8);
printk("dspp the data C is 0x%x!\n",addri);


for(i=0;i<32;i++)
{

printk("0x%x!",*(p+i));
if(i%16==15)
printk("\n");
}
for(i=0;i<32;i++)
{

printk("0x%x!",*(q+i));
if(i%16==15)
printk("\n");
}
for(i=0;i<32;i++)
{

printk("0x%x!",*(r+i));
if(i%16==15)
printk("\n");
}
/*娴嬭瘯鑾峰彇鏁版嵁base1,start the interrupt*/
addri=0x02000020;
writel(addri,iomembase1+0x4);

}
void __exit cleanup_module(void)
{
for(i=0;i<32;i++)
{

printk("0x%x!",*(r+i));
if(i%16==15)
printk("\n");
}
kfree(p);
kfree(q);
kfree(r);
kfree(s);


/*閲婃斁io鍐呭瓨鏄犲皠*/
iounmap(iomembase0);
iounmap(iomembase1);
/*閲婃斁娉ㄥ唽*/
release_mem_region(base0start,base0len);
release_mem_region(base1start,base1len);




/*绂佺敤璁惧*/
pci_disable_device(jmkdev);
/*鏂芥斁鍐呭瓨*/

unregister_chrdev(jmk_major,"jmkdev");
printk("Goodbye cruel world!\n");
}
回复
strategist 2006-02-17
我先把硬件相关说明写一下:

程序中要用到的参数
CLASS_CODE FF0000H
DEVICE_ID 0004H
VENDOR_ID 1172H

软件的接口:
本设备实现了两个BAR (BAR0,BAR1)。
BAR0 映射了1Kbytes 的memory space。它映射了设备中一个1Kbytes的sram(256*32bits)。

BAR1 映射了1Kytes 的 memory space。其有效的地址空间是00h 至 07h(8 bytes)。 它映射了设

备DMA的两个32bit的寄存器。

产生中断:
在对BAR1 中映射的Block_Parameter 这个32位寄存器进行写操作(地址是04H-07H)。
Block_Parameter的layout如下:

bar1 04h block parameter
[31-24] [23-0]
block number block size

校验组有三个数据块,数据块的大小是64KB。
对Block_Parameter寄存器写入 03010000H 。
当完成对上述写操作后,硬件的会自动根据程序提供的地址去取数据,进行XOR运算,待全部数据块

的XOR运算都结束后,它会将校验结果存放到内存的制定位置去,然后发中断通知OS。

清中断:
校验结果计算完成、写回内存后,设备发中断。程序若要清中断,对BAR1中的INT_CLEAR寄存器进行

读操作(INT_CLEAR为32位、地址是00H至03H)。设备只有检测到对INT_CLEAR寄存器的读操作,才会置

中断信号无效,否则会一直置中断有效。
注: 对上述 所有地址的写操作、读操作 要以32位的方式进行。

回复
strategist 2006-02-16
急切地呼唤牛人的出现
回复
相关推荐
发帖
Linux_Kernel
创建于2007-08-27

4147

社区成员

Linux/Unix社区 内核源代码研究区
申请成为版主
帖子事件
创建了帖子
2006-02-16 09:59
社区公告
暂无公告