|
struct ep3cxx_device_info {
unsigned char flag;
struct device *dev;
struct resource *men[RESOURCE_NUM];
void __iomem *base[RESOURCE_NUM];
//spinlock_t lock;
//struct semaphore sem;
int irq;
//wait_queue_head_t wait_read;
//wait_queue_head_t wait_write;
unsigned char rev_flag[FLAG_NUM];
unsigned char wr_flag[FLAG_NUM];
unsigned char rev_skb[PORT_NUM][RE_SIZE];
unsigned char wr_skb[PORT_NUM][WR_SIZE];
};
// 定义中断底半部函数并关联
static void ep3cxx_interrupt_bottom(unsigned long arg);
DECLARE_TASKLET(ep3cxx_tasklet, ep3cxx_interrupt_bottom, 0);
// ep3cxx所需要的资源情况,根据硬件的不同这个需要修改
struct resource ep3cxx_resource[] = {
[0]={
.start = S3C6410_SROMC_BASE,
.end = S3C6410_SROMC_BASE + S3C6410_SRMOC_LEN,
.flags = IORESOURCE_MEM,
},
[1]={
.start = S3C6410_GPO_BASE,
.end = S3C6410_GPO_BASE + S3C6410_GPO_LEN,
.flags = IORESOURCE_MEM,
},
[2]={
.start = S3C6410_SROM_CS5,
.end = S3C6410_SROM_CS5 + S3C6410_SROM_CS5_LEN,
.flags = IORESOURCE_MEM,
},
[3]={
.start = S3C6410_GPN_BASE,
.end = S3C6410_GPN_BASE + S3C6410_GPN_LEN,
.flags = IORESOURCE_MEM,
},
[4]={
.start = S3C6410_EXINT_CON_BASE,
.end = S3C6410_EXINT_CON_BASE + S3C6410_EXINT_CON_LEN,
.flags = IORESOURCE_MEM,
},
[5]={
.start = S3C6410_VIC1_BASE,
.end = S3C6410_VIC1_BASE + S3C6410_VIC1_LEN,
.flags = IORESOURCE_MEM,
},
[6]={
.start = FPGG_IRQ_EXINT,
.end = FPGG_IRQ_EXINT,
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
}
};
/*******************************************************************************************
Function: static irqreturn_t ep3cxx_interrupt_handle( int irq, void* dev_id )
Description: 外部中断时的顶部处理函数
Input: int irq
void* dev_id
Return:
Others:
*******************************************************************************************/
static irqreturn_t ep3cxx_interrupt_handle( int irq, void* dev_id )
{
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
return IRQ_HANDLED;
}
/*******************************************************************************************
Function: static void ep3cxx_release(struct device * dev)
Description: 当执行驱动卸载的时候调用此函数
Input: struct device * dev
Return:
Others:
*******************************************************************************************/
static void ep3cxx_release(struct device * dev)
{
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
}
// ep3cxx_device为一个平台设备
struct platform_device ep3cxx_device= {
.name = DEV_NAME,
.id = -1,
.num_resources = ARRAY_SIZE(ep3cxx_resource),
.resource = ep3cxx_resource,
.dev =
{
.release = ep3cxx_release,
}
};
/*******************************************************************************************
Function: static int fpga_ep3cxx_open(struct inode *inode,struct file *filp)
Description: fpga ep3cxx open函数,提供给实现应用程序中open函数的功能
Input: struct inode *inode
struct file *filp
Return: 0为成功,非0为失败
Others: 这个是linux实现标准函数
*******************************************************************************************/
static int fpga_ep3cxx_open(struct inode *inode,struct file *filp)
{
struct ep3cxx_device_info *info = platform_get_drvdata(&ep3cxx_device);
DEBUG(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
if(request_irq(info->irq, ep3cxx_interrupt_handle, IRQF_DISABLED | IRQF_TRIGGER_RISING, DEV_NAME, info ))
{
printk("fail to install irq\n");
return -EAGAIN;
}
filp->private_data = info;
return 0;
}
/*******************************************************************************************
Function: static ssize_t fpga_ep3cxx_read(struct file *filp,char __user *buffer,size_t size,loff_t *offset)
Description: fpga ep3cxx open函数,提供给实现应用程序中open函数的功能
Input: struct file *filp
char __user *buffer
size_t size
loff_t *offset
Return: 0为成功,非0为失败
Others: 这个是linux实现标准函数
*******************************************************************************************/
static ssize_t fpga_ep3cxx_read(struct file *filp,char __user *buffer,size_t size,loff_t *offset)
{
}
/*******************************************************************************************
Function: static ssize_t fpga_ep3cxx_write(struct file *filp,const char __user *buffer,size_t size,loff_t *offset)
Description: 这个函数是上层write函数的实现,当上层函数调用write的时候,就会直接调用此函数
Input: struct inode *inode
const char __user *buffer
size_t size
loff_t *offset
Output: 无
Return: 0为成功,非0为失败
Others:
*******************************************************************************************/
static ssize_t fpga_ep3cxx_write(struct file *filp,const char __user *buffer,size_t size,loff_t *offset)
{
}
/*******************************************************************************************
Function: static int fpga_ep3cxx_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
Description: 这个函数是上层write函数的实现,当上层函数调用write的时候,就会直接调用此函数
Input: struct inode *inode
struct file *filp
unsigned int cmd
unsigned long arg
Return: 0为成功,非0为失败
Others:
*******************************************************************************************/
static int fpga_ep3cxx_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
}
/*******************************************************************************************
Function: static void ep3cxx_interrupt_bottom(unsigned long arg)
Description: 外部中断时的底部处理函数
Input: unsigned long arg
Return: void
Others:
*******************************************************************************************/
static void ep3cxx_interrupt_bottom(unsigned long arg)
{
}
/*******************************************************************************************
Function: static unsigned int fpga_ep3xx_poll(struct file *filp, poll_table *wait)
Description:
Input: struct file *filp
poll_table *wait
Return:
Others:
*******************************************************************************************/
static unsigned int fpga_ep3xx_poll(struct file *filp, poll_table *wait)
{
}
/*******************************************************************************************
Function: static int fpga_ep3cxx_release(struct inode *inode,struct file *filp)
Description: 当执行close的时候执行此函数
Input: struct inode *inode
struct file *filp
Return:
Others:
*******************************************************************************************/
static int fpga_ep3cxx_release(struct inode *inode,struct file *filp)
{
struct ep3cxx_device_info *release_info = filp->private_data;
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
free_irq(release_info->irq, release_info);
release_info = NULL;
return 0;
}
struct file_operations fpga_ep3cxx_opt ={
.owner = THIS_MODULE,
.ioctl = fpga_ep3cxx_ioctl,
.open = fpga_ep3cxx_open,
.read = fpga_ep3cxx_read,
.write = fpga_ep3cxx_write,
.release = fpga_ep3cxx_release,
.poll = fpga_ep3xx_poll,
};
static struct miscdevice ep3cxx_dev_misc ={
.minor = MISC_DYNAMIC_MINOR,
.name = MISC_DEV_NAME,
.fops = &fpga_ep3cxx_opt,
};
/*******************************************************************************************
Function: static int ep3cxx_probe ( struct platform_device *dev )
Description: 这个是驱动探测函数,当驱动加载到内核的时候调用此函数,实现设备,资源等的注_册
Input: struct platform_device *dev
Return: 0为成功,非0为失败
Others: 这个是驱动里面最重要的函数,驱动靠这个函数注_册进入内核里
函数主要实现下面的功能:
1,申请虚拟的内存,然后把需要访问的物理内存映射到虚拟内存空间
2,使用虚拟内存后,设置各个寄存器,设置SROMC控制器来控制bank5,
设置GPIO的控制器,来配置GPIO_O3为CS5,然后配置中断INIT15引脚的
配置
*******************************************************************************************/
static int __devinit ep3cxx_probe ( struct platform_device *dev )
{
struct ep3cxx_device_info *priv_info = NULL;
struct resource *res = NULL;
int ret = 0;
int size = 0;
unsigned int resource_num = 0;
unsigned int cnt = 0;
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
priv_info = kzalloc(sizeof(struct ep3cxx_device_info), GFP_KERNEL);
if (!priv_info) {
printk("kzalloc is fail!\n\n");
ret = -ENOMEM;
goto err_out;
}
/* get the num of not initerrupt of resource */
resource_num = RESOURCE_NUM;
for(cnt = 0; cnt < resource_num; cnt++)
{
res = platform_get_resource( dev, IORESOURCE_MEM, cnt );
if (NULL == res)
{
printk("no memory resource %d\n", cnt);
ret = -ENOENT;
goto err_out_kfree;
}
size = (res->end-res->start)+1;
priv_info->men[cnt] = request_mem_region(res->start, size, dev->name);
if (NULL == priv_info->men[cnt])
{
printk("failed to get memory %d\n", cnt);
ret = -ENOENT;
goto err_release;
}
priv_info->base[cnt] = ioremap(res->start, size);
if (NULL == priv_info->base[cnt])
{
printk("failed to ioremap %d\n", cnt);
ret = -EINVAL;
goto err_iounmap;
}
}
ep3cxx_dev_misc.parent = &dev->dev;
ret=misc_register(&ep3cxx_dev_misc);
if(ret)
{
printk("cannot register ep3cxx_dev_misc miscdev!\n");
goto err_misc;
}
priv_info->dev = &dev->dev;
// 申请中断资源
priv_info->irq = platform_get_irq(dev, 0);
printk("priv_info->irq = %d\n", priv_info->irq);
if(priv_info->irq < 0)
{
printk("get irq resource fail\n");
ret = -ENXIO;
goto err_irq;
}
// 初始化读等待队列
//init_waitqueue_head(&priv_info->wait_read);
//init_waitqueue_head(&priv_info->wait_write);
// 初始化自旋锁
//spin_lock_init(&priv_info->lock);
// 初始化信号量
//init_MUTEX(&priv_info->sem);
// 设置SROMC控制器,片选区域为bank5 写S3C6410_SROM_BC5寄存器,主要是设置时序
// S3C_SROM_BW 31~24 23~20 19~16 15~12 11~8 7~4 3~0
// reserved Memory bank5 Memory bank4 Memory bank3 Memory bank2 Memory bank1 Memory bank0
iowrite32((ioread32(priv_info->base[SROMC]+S3C6410_SROM_BW) & ~(0xF<<20)) | (0x3<<22), priv_info->base[SROMC]+S3C6410_SROM_BW);
iowrite32((0x0<<28)|(0x4<<24)|(0xd<<16)|(0x1<<12)|(0x4<<8)|(0x6<<4)|(0x0<<0), priv_info->base[SROMC]+S3C6410_SROM_BC5);
// 配置GPIO_O5为MEM0_nCS[5] bit 7:6 = 10 O5为上拉 GPN15为中断 GPN15为上拉
iowrite32((ioread32(priv_info->base[GPO]+S3C6410_GPNCON) & ~(0x3<<6)) | (0x2<<6), priv_info->base[GPO]+S3C6410_GPNCON);
iowrite32((ioread32(priv_info->base[GPO]+S3C6410_GPNPUD) & ~(0x3<<6)) | (0x2<<6), priv_info->base[GPO]+S3C6410_GPNPUD);
iowrite32((ioread32(priv_info->base[GPN]+S3C6410_GPNCON) & ~(0x3<<30)) | (0x2<<30), priv_info->base[GPN]+S3C6410_GPNCON);
iowrite32((ioread32(priv_info->base[GPN]+S3C6410_GPNPUD) & ~(0x3<<30)) | (0x2<<30), priv_info->base[GPN]+S3C6410_GPNPUD);
// 设置中断的模式: 000 = Low level 001 = High level 01x = Falling edge triggered
// 11x = Both edge triggered 10x = Rising edge triggered
iowrite32((ioread32(priv_info->base[EXINT]+S3C6410_EINT0CON0) & ~(0x7 <<28)) | (0x2 << 28), priv_info->base[EXINT]+S3C6410_EINT0CON0);
iowrite32((ioread32(priv_info->base[EXINT]+S3C6410_EINT0FLTCON1) & ~(0x3 <<30)) | (0x1 << 31), priv_info->base[EXINT]+S3C6410_EINT0FLTCON1);
iowrite32((ioread32(priv_info->base[EXINT]+S3C6410_EINT0PEND) & ~(0x1<<15)), priv_info->base[EXINT]+S3C6410_EINT0PEND);
iowrite32((ioread32(priv_info->base[EXINT]+S3C6410_EINT0MASK) & ~(0x1<<15)), priv_info->base[EXINT]+S3C6410_EINT0MASK);
iowrite32((ioread32(priv_info->base[EXINT]+S3C6410_VIC1INTENABLE) & ~(0x1<<1)) | (0x1 << 0), priv_info->base[EXINT]+S3C6410_VIC1INTENABLE);
/* set the platform_drvdata */
platform_set_drvdata(dev, priv_info);
return ret;
err_iounmap:
switch(cnt)
{
case SROMC: goto err_iounmap0;
case GPO: goto err_iounmap1;
case CS5: goto err_iounmap2;
case GPN: goto err_iounmap3;
case EXINT: goto err_iounmap4;
case VIC1: goto err_iounmap5;
default: goto err_out;
}
err_release:
switch(cnt)
{
case SROMC: goto err_release0;
case GPO: goto err_release1;
case CS5: goto err_release2;
case GPN: goto err_release3;
case EXINT: goto err_release4;
case VIC1: goto err_release5;
default: goto err_out;
}
err_irq:
misc_deregister(&ep3cxx_dev_misc);
err_misc:
err_iounmap5:
iounmap(priv_info->base[VIC1]);
err_release5:
release_resource(priv_info->men[VIC1]);
err_iounmap4:
iounmap(priv_info->base[EXINT]);
err_release4:
release_resource(priv_info->men[EXINT]);
err_iounmap3:
iounmap(priv_info->base[GPN]);
err_release3:
release_resource(priv_info->men[GPN]);
err_iounmap2:
iounmap(priv_info->base[CS5]);
err_release2:
release_resource(priv_info->men[CS5]);
err_iounmap1:
iounmap(priv_info->base[GPO]);
err_release1:
release_resource(priv_info->men[GPO]);
err_iounmap0:
iounmap(priv_info->base[SROMC]);
err_release0:
release_resource(priv_info->men[SROMC]);
err_out_kfree:
kfree(priv_info);
err_out:
printk("ep3cxx probe is fail!\n");
return ret;
}
/*******************************************************************************************
Function: static int ep3cxx_remove ( struct platform_device *dev )
Description: 驱动移除函数,与probe函数进行相反的工作
Input: struct platform_device *dev
Return:
Others:
*******************************************************************************************/
static int __devexit ep3cxx_remove ( struct platform_device *dev )
{
unsigned int remove_num = RESOURCE_NUM;
struct ep3cxx_device_info *priv = platform_get_drvdata(dev);
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
platform_set_drvdata(dev, NULL);
misc_deregister(&ep3cxx_dev_misc);
while(remove_num--)
{
iounmap(priv->base[remove_num]);
release_resource(priv->men[remove_num]);
}
kfree(priv);
return 0;
}
static struct platform_driver ep3cxx_driver = {
.probe = ep3cxx_probe,
.remove = __devexit_p(ep3cxx_remove),
.driver = {
.owner = THIS_MODULE,
.name = DEV_NAME,
},
};
/*******************************************************************************************
Function: static int __init ep3cxx_init ( void )
Description:
Input:
Return:
Others:
*******************************************************************************************/
static int __init ep3cxx_init ( void )
{
int ret = 0;
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
ret = platform_device_register ( &ep3cxx_device );
if ( ret )
{
platform_device_unregister ( &ep3cxx_device );
printk ( "platform_device_register is fail!\n" );
return ret;
}
printk ( "platform_device_register is ok!\n" );
ret = platform_driver_register ( &ep3cxx_driver );
if ( ret )
{
printk ( "platform_driver_register is fail!\n" );
platform_driver_unregister ( &ep3cxx_driver );
return ret;
}
printk ( "platform_driver_register is ok!\n" );
return ret;
}
/*******************************************************************************************
Function: static void __exit ep3cxx_exit ( void )
Description:
Input:
Return:
Others:
*******************************************************************************************/
static void __exit ep3cxx_exit ( void )
{
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
platform_driver_unregister ( &ep3cxx_driver );
platform_device_unregister ( &ep3cxx_device );
}
module_init ( ep3cxx_init );
module_exit ( ep3cxx_exit );
以上是我的代码,有部分没有实现的:
[root@Clou ep3cxx_new]# insmod ep3cxx_new.ko
ep3cxx_init:Oct 28 2010,15:17:19
platform_device_register is ok!
ep3cxx_probe:Oct 28 2010,15:17:19
priv_info->irq = 79
platform_driver_register is ok!
[root@Clou ep3cxx_new]# ./ep3cxx
<1>fpga_ep3cxx_open:Oct 28 2010,15:17:19
##################################################
ep3cxx_interrupt_handle:Oct 28 2010,15:17:19
ep3cxx_interrupt_handle:Oct 28 2010,15:17:19
ep3cxx_interrupt_handle:Oct 28 2010,15:17:19
ep3cxx_interrupt_handle:Oct 28 2010,15:17:19
ep3cxx_interrupt_handle:Oct 28 2010,15:17:19
ep3cxx_interrupt_handle:Oct 28 2010,15:17:19
ep3cxx_interrupt_handle:Oct 28 2010,15:17:19
ep3cxx_interrupt_handle:Oct 28 2010,15:17:19
fpga_ep3cxx_release:Oct 28 2010,15:17:19
[root@Clou ep3cxx_new]#
这里我用ctrl+c推出了,上面是我用按键模拟的一个外部中断,按下按键会有上面的打印信息。
现在我推出程序后,就是close后,释放中断后,我在按下按键来模拟外部中断,就会出现下面的错误,这个现象在执行rmmod xx.ko也会出现!
(只要申请中断后就会出现这个现象)
BUG: soft lockup - CPU#0 stuck for 11s! [swapper:0]
Pid: 0, comm: swapper
CPU: 0 Not tainted (2.6.24.2 #460)
PC is at __do_softirq+0x48/0xc0
LR is at irq_exit+0x44/0x4c
pc : [<c00a4d60>] lr : [<c00a5108>] psr: 20000113
sp : c03efee0 ip : c03eff10 fp : c03eff0c
r10: 00000000 r9 : c0426ad8 r8 : 00000001
r7 : c04257e0 r6 : 0000000a r5 : 00000002 r4 : 0000001c
r3 : c03ee000 r2 : 00000100 r1 : c04257e0 r0 : 0000001c
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 00c5387f Table: 550a0008 DAC: 00000017
[<c0088444>] (show_regs+0x0/0x50) from [<c00c0b5c>] (softlockup_tick+0xec/0x11c)
r4:0000002a
[<c00c0a70>] (softlockup_tick+0x0/0x11c) from [<c00a8f20>] (run_local_timers+0x18/0x1c)
[<c00a8f08>] (run_local_timers+0x0/0x1c) from [<c00a8fa0>] (update_process_times+0x2c/0x58)
[<c00a8f74>] (update_process_times+0x0/0x58) from [<c008ade0>] (timer_tick+0xcc/0xec)
r5:00000000 r4:c0426e10
[<c008ad14>] (timer_tick+0x0/0xec) from [<c0097a1c>] (s3c_timer_interrupt+0x24/0x54)
r5:00000000 r4:c0426e10
[<c00979f8>] (s3c_timer_interrupt+0x0/0x54) from [<c00c0e80>] (handle_IRQ_event+0x3c/0x74)
r4:c03f6568
[<c00c0e44>] (handle_IRQ_event+0x0/0x74) from [<c00c2738>] (handle_level_irq+0xd4/0xf0)
r7:c04257e0 r6:c03eff40 r5:0000001c r4:c03fbc0c
[<c00c2664>] (handle_level_irq+0x0/0xf0) from [<c0086048>] (__exception_text_start+0x48/0x64)
r5:c03fbc0c r4:0000001c
[<c0086000>] (__exception_text_start+0x0/0x64) from [<c0086a70>] (__irq_svc+0x30/0x80)
Exception stack(0xc03efe98 to 0xc03efee0)
fe80: 0000001c c04257e0
fea0: 00000100 c03ee000 0000001c 00000002 0000000a c04257e0 00000001 c0426ad8
fec0: 00000000 c03eff0c c03eff10 c03efee0 c00a5108 c00a4d60 20000113 ffffffff
r6:10000000 r5:f4600000 r4:ffffffff
[<c00a4d18>] (__do_softirq+0x0/0xc0) from [<c00a5108>] (irq_exit+0x44/0x4c)
[<c00a50c4>] (irq_exit+0x0/0x4c) from [<c008604c>] (__exception_text_start+0x4c/0x64)
[<c0086000>] (__exception_text_start+0x0/0x64) from [<c0086a70>] (__irq_svc+0x30/0x80)
Exception stack(0xc03eff40 to 0xc03eff88)
ff40: 00000002 c622b5e0 f6800000 00000021 c00885cc c03ee000 c00885cc c0412f68
ff60: 50022088 410fb766 50022054 c03eff94 c03eff88 c03eff88 c00905d0 c0088624
ff80: a0000013 ffffffff
r6:10000000 r5:f4600000 r4:ffffffff
[<c00885cc>] (default_idle+0x0/0x64) from [<c0088398>] (cpu_idle+0x34/0x50)
[<c0088364>] (cpu_idle+0x0/0x50) from [<c03254e4>] (rest_init+0x50/0x60)
r7:c03f1db8 r6:c0023f28 r5:c0412b28 r4:c042815c
[<c0325494>] (rest_init+0x0/0x60) from [<c0008d5c>] (start_kernel+0x250/0x2bc)
[<c0008b0c>] (start_kernel+0x0/0x2bc) from [<50008034>] (0x50008034) |
阿莫论坛20周年了!感谢大家的支持与爱护!!
你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
|