Пишу драйвер для одного PCI устройства, для ядра 2.4.32. Устройство
представляет собой отладочную плату TI. Драйвер запрашивает у
устройства передачу данных по DMA. Для этого он записывает в mailbox
команду, необходимые данные и вызывает прерывание. Далее устройство
считывает mailbox и выставляет ответное прерывание, что данные
прочитаны, и начинает передавать данные через DMA. По окончании
передачи данных выставляется второе прерывание. Из юзерспейса запрос
данных от устройства происходит через IOCTL. В программе из
юзерйспейса я создаю нить pthread и в неё дергую ioctl устройства,
проблема в том что если я корректно завершаю работу приложения и
дожидаюсь завершения нити все работает хорошо, но стоит мне убить
приложение некорректно (через kill) или закрыть терминал, то компьютер
наглухо виснет. Еще проблема в том что драйвер не работает на SMP
машинах :) Ниже привожу код ioctl
case IOCTL_GETRAW:
volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *)
((Uint32) regVirt + (DM64LCPCI_PCIREG_BASE - 0x01C00000));
int i,n,CommandCode;
SC_GT_ELEMENT *sglmb;
char *data;
int *r=((int*)ioctl_param);
DECLARE_WAITQUEUE(wait, current);
CommandCode = RW_CMD_READ_RAW_FRAME;
#ifdef _USE_DEBUG
printk("Board: got Xfer CMD %i\n",CommandCode);
#endif
// Here we lock our spin
spin_lock(&sl);
if (!expack[CommandCode])
init_waitqueue_head(wq+CommandCode);
expack[CommandCode]=RW_CARD_CMD(CommandCode);
expack[0]=RW_CARD_CMD(CommandCode);
mb->HostRequest.CommandCode=RW_HOST_CMD(CommandCode);
mb->HostRequest.Info=1;
mb->CardRequest[CommandCode].CommandCode=NULL_CMD;
mb->CardRequest[CommandCode].Info=0;
mb->CardRequest[0].CommandCode=NULL_CMD;
sglmb = mb->Sc_Gt_Element;
sglmb->Adress = cpu_to_le32(virt_to_bus(pvksdev->raw_buf));
sglmb->Length = cpu_to_le32(0x100000);
#ifdef _USE_DEBUG
printk("Board: phys of xferBuf = 0x%x\n", mb->Sc_Gt_Element[0].Adress);
printk("Board: len of xferBuf = 0x%x\n", mb->Sc_Gt_Element[0].Length);
printk("Board: set IRQ%i 4 DSP\n", CommandCode);
#endif
pciRegs->PCISTATSET = TRIGGER_DSPINT_MASK;
sti();
for(i=0;i<0x10000;i++)
{
if(expack[0]==0x3AEB1C)
{
#ifdef _USE_DEBUG
printk("Board: SGL%i read after %i waiting",CommandCode,i);
#endif
break;
}
}
if(expack[0]!=0x3AEB1C)
{
#ifdef _USE_DEBUG
printk("Board: cant get SGL%i read!!!",CommandCode);return -2101;
#endif
}
#ifdef _USE_DEBUG
printk("Board: releasing spinlock%i...",CommandCode);
#endif
cli();
spin_unlock(&sl);
if(expack[CommandCode]!=0x3AEB1C)
{
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(wq+CommandCode, &wait);
schedule();
sti();
if(signal_pending(current))
{
#ifdef _USE_DEBUG
printk("Board: signal%i pending\n",CommandCode);
#endif
return -2100;
}
else
{
#ifdef _USE_DEBUG
printk("Board: signal%i not pending\n",CommandCode);
#endif
}
remove_wait_queue(wq+CommandCode, &wait);
}
else
{
#ifdef _USE_DEBUG
printk("Board: Xfer%i ALREADY done: no need wait\n",CommandCode);
#endif
}
n=mb->CardRequest[CommandCode].Info;
#ifdef _USE_DEBUG
printk("Board: Receive %d bytes of raw frame\n", n);
#endif
if (n > 0 && n < 0x100000)
copy_to_user(r, (const void*)pvksdev->raw_buf, n);
return n;
}
И еще ниже обработчик прерывания от платы:
static void ISR_handler5 (int irq, void * arg, struct pt_regs * flags)
{
Uint32 status = HAL_CheckPciInterrupt () ;
volatile DM64LCPCI_pciRegs * pciRegs = (DM64LCPCI_pciRegs *)((Uint32)regVirt+ (DM64LCPCI_PCIREG_BASE - 0x01c00000));
int i,j,k,l,m,n;
IO_REQUEST*r=(IO_REQUEST*)&mb->HostRequest;
if (status == 1)
{
#ifdef _USE_DEBUG
printk ("Board: Got DSPIRQ\n") ;
#endif
r = (IO_REQUEST*)&mb->CardRequest;
for( i = 0; i < 5; i++)
{
if((j=r->CommandCode) != NULL_CMD)
{
if(expack[i]==j)
{
expack[i]=0x3AEB1C;
if(i)
{
#ifdef _USE_DEBUG
printk("Board: WAKE ch%i ioQ.\n",i);
#endif
wake_up_interruptible(wq+i);}
else
{
#ifdef _USE_DEBUG
printk("Board: SGL ch%i OK.\n",j&0xFF);
#endif
}
}
else
{
r->CommandCode=NULL_CMD;
}
r->CommandCode=NULL_CMD;
}
r++;
}
HAL_PciClearDspInterrupt () ;
}
return;
}
Буду признателен за любые советы и замечания.
Спасибо за ответ, проблему увидел, осознал, код не мой, мне надо разобраться со всем этим хламом, и заставить его работать нормально, wait_event_interruptible это именно то, что мне было нужно, спасибо!