我在调试一个语音驱动,语音codec是cp1306
在open函数中我申请了DMA通道,在read/write函数中等待interruptible_sleep_on(&ssi_rwait);
在DMA完成中,wake_up_interruptible(&ssi_rwait);
结果我第一次调用read/write函数时候,程序就停在interruptible_sleep_on(&ssi_rwait);
我ctrl+C后,再调用驱动时候,就OK了,不知道这个是什么原因?
具体代码如下:
static devfs_handle_t devfs_handle;
int init_module()
{
int result;
printk("ssi649 driver version 1.0 "__DATE__" / "__TIME__"\n");
result = devfs_register_chrdev(0, "SSI649", &ssi649_fops);
if ( result < 0 )
{
printk("ssi649 error: Unable to register driver\n");
return -ENODEV;
}
devfs_handle =devfs_register(NULL, "SSI649", DEVFS_FL_DEFAULT,
result, 0,
S_IFCHR | S_IRUSR | S_IWUSR,
&ssi649_fops, NULL);
gMajor = result;
if(malloc_buffer()<0)
printk("ERROR: can't malloc buffer\n");
//set mode
_reg_CRM_CSCR &= ~0x180000; /* ssi1 ssi2 SEL */
_reg_CRM_PCCR0 |= 0x320d0; /* 3 ssi1,2 baud En; 2 dma En;
5 cspi1 ssi1 ssi2 En */
_reg_CRM_PCCR1 |= 0x800000; /* cspi3 En *///add: cspi3 en
//_reg_CRM_CCSR = 0xf; /* ssi1 baud output */
_reg_CRM_CCSR = 0xf; /* ssi2 baud output */
return 0;
}
static int ssi649_open(struct inode *inode, struct file *filp)
{
MOD_INC_USE_COUNT;
dma_request_t ssi_dma_req ;
memset(&ssi_dma_req, 0, sizeof(dma_request_t));
if ((mx_request_dma(&channel_mem2ssi, "SSISTX"))>=0)
{
/* Configure the dma request members that do not change */
ssi_dma_req.burstLength = 8;
ssi_dma_req.callback = (dma_callback_t)ssiTX_complete_handler;
/* dma source config */
ssi_dma_req.sourceType = DMA_TYPE_LINEAR;
ssi_dma_req.sourcePort = DMA_MEM_SIZE_32;
/* dma dest config */
ssi_dma_req.destType = DMA_TYPE_FIFO;
ssi_dma_req.destAddr = (uint32_t *)0x10011000; //SSI1 Tx data register 0
ssi_dma_req.destPort = DMA_MEM_SIZE_8;
// request config
ssi_dma_req.request = 9; /* request source: SSI2 TX0 FIFO */
_reg_DMA_CCR(channel_mem2ssi) |= 1<<3;
_reg_DMA_RTOR(channel_mem2ssi) = 0x0;
mx_dma_set_config(channel_mem2ssi, &ssi_dma_req);
}
else
{
printk(" Failed to acquire TX DMA\n");
}
memset(&ssi_dma_req,0,sizeof(dma_request_t));
if (( mx_request_dma(&channel_ssi2mem,"SSISRX")) >=0 )
{
// Configure the dma request members that do not change
ssi_dma_req.burstLength = 8;
// DMA interrupt config
ssi_dma_req.callback = (dma_callback_t)ssiRX_complete_handler;
// source config
ssi_dma_req.sourceType = DMA_TYPE_FIFO;
ssi_dma_req.sourceAddr = (uint32_t *)0x10011008; //SSI1 Rx data register 0
ssi_dma_req.sourcePort = DMA_MEM_SIZE_8;
// dest config
ssi_dma_req.destType = DMA_TYPE_LINEAR;
ssi_dma_req.destPort = DMA_MEM_SIZE_32;
// request config
ssi_dma_req.request = 8; /* request source: SSI2 RX0 FIFO */
_reg_DMA_CCR(channel_ssi2mem) |= 1<<3;
_reg_DMA_RTOR(channel_ssi2mem) = 0x0;
mx_dma_set_config(channel_ssi2mem, &ssi_dma_req);
}
else
{
printk(" Failed to acquire RX DMA");
}
return 1;
}
static ssize_t ssi649_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
if(mm>300)
{
mm=0;
rdata_buf=rdata_buf3;
}
rdata_buf=rdata_buf+count/4;
dma_phyraddr = virt_to_bus((void *)rdata_buf);
mm++;
_reg_DMA_DAR(channel_ssi2mem) = dma_phyraddr;
_reg_DMA_CNTR(channel_ssi2mem) =count;
_reg_DMA_CCR(channel_ssi2mem) = 0x818;
enable_dma(channel_ssi2mem);
interruptible_sleep_on(&ssi_rwait);
copy_to_user(buf,rdata_buf,count);
return 1;
}
static void ssiTX_complete_handler(void* arg)
{
uint32_t status = *(uint32_t *)arg;
if(status & DMA_DONE)
{
if (_reg_SSI_SISR(SSI2) & (1<<10))
{
pr_debug("!!!!! RX FIFO Overrun!\n");
}
//DMAbuf_inputintr(dbmx_audiodev);
_reg_DMA_DISR=(1<
_reg_DMA_CCR(channel_mem2ssi) &= ~0x1;
}
else
{
if (status & DMA_BURST_TIMEOUT)
printk("%s: DMA_BURST_TIMEOUT\n", __FUNCTION__);
if (status & DMA_TRANSFER_ERROR)
printk("%s: DMA_TRANSFER_ERROR\n", __FUNCTION__);
if (status & DMA_BUFFER_OVERFLOW)
printk("%s: DMA_BUFFER_OVERFLOW\n", __FUNCTION__);
if (status & DMA_REQUEST_TIMEOUT)
printk("%s: DMA_REQUEST_TIMEOUT\n", __FUNCTION__);
mx_dump_dma_register(channel_mem2ssi);
}
_reg_DMA_DISR=(1<
_reg_DMA_CCR(channel_mem2ssi) &= ~0x1;
wake_up_interruptible(&ssi_twait);
}
程序第一次调用的时候就停在interruptible_sleep_on(&ssi_rwait);
第二次和以后就过去了,一点事也没有,这个是什么原因,请高手们指教!
是不是第一次调用的时候有些步骤没有成功,比如enable_dma(channel_ssi2mem);
建议检查返回值,判断是否成功,也可以调用两次测试一下
extern void enable_dma(dmach_t channel); 这个没有返回值的
不过我在ssi1306_write加上这个,就能解决一下这个问题,不过感觉治标不治本
if(gFlag_First!=1)
{
interruptible_sleep_on(&ssi_twait);
}
gFlag_First = 2;
ssi1306_write和ssi1306_read其实没有什么区别的
static ssize_t ssi1306_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
copy_from_user(rdata_buf1,buf,count);
_reg_DMA_SAR(channel_mem2ssi) = dma_phyraddr1;
_reg_DMA_CNTR(channel_mem2ssi) =count;
enable_dma(channel_mem2ssi);
if(gFlag_First!=1)
{
interruptible_sleep_on(&ssi_twait);
}
gFlag_First = 2;
return 1;
}