Пишу драйвер для одного 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;
}
Буду признателен за любые советы и замечания.
Необходимо ATAPI CD-ROM драйву, по ATAPI отсылать комманду (не стандартную). Есть софт под Windows который это делает, теперь мне надо сделать тоже самое в Linux. Так как экспиренса особого нет в Linux ATAPI специфики, у меня возник вопрос. Можно ли из userspace отослать произвольную ATAPI команду ATAPI устройству. Или для этого нужно писать/модифицировать драйвер. Как варинт есть идея модифицировать драйвер ide-cd. Есть ли еще варианты?
Есть pppd работающий в режиме on demand. И программа которая по некоторому событию начинает соединяться с удалённым сервером. Когда pppd установил соединение он переписывает файл resolv.conf, прописываю туда адреса DNS серверов провайдера. А программа ресолвит имена через gethostbyname и даже после того как файл resolv.conf был переписан не может отресолвить имя удаленного хоста. Только если прервать работу программы и запустить её заново, всё ресолвиться замечательно. Вопрос, как заставить программу без перезапуска обновлять информацию о DNS серверах?
Есть плата с DSP процессором от SpectrumDigital. У платы есть PCI
интерфейс. Вместе с платой шёл пример работы с PCI сделанный с помощью
Jungo, в примере можно почитать/пописать память устройства и.т.д.
Теперь мне бы хотелось написать драйвер для этой платы под Linux,
который для начала мог бы моргать светодиодами на самой плате. Я
написал простой дарйвер, который находит эту плату, определяет её
ресурсы (там два MMIO) и делает ioremap. Теперь я хотел бы через
writeb записать в регистр определящий состояние светодиодов своё
значение.
В примере идущим с платой есть файл dm642_lib.h
в нём есть следующие определения.
#define kBaseAddr_CE0 (0x80000000u)
#define kBaseAddr_CE1 (0x90000000u)
#define kBaseAddr_CE2 (0xA0000000u)
#define kBaseAddr_CE3 (0xB0000000u)
#define kFpgaAmrOffs (0x00080010)
#define kFpgaAmrBaseAddress (kBaseAddr_CE1 + kFpgaAmrOffs)
enum
{
kFamrOffs_OSDCR = kFpgaAmrOffs, // OSD Control Reg => 0x9008_0010
kFamrOffs_DMATLR, // DMA Threshold LSB Reg => 0x9008_0011
kFamrOffs_DMATMR, // DMA Threshold MSB Reg => 0x9008_0012
kFamrOffs_ISR, // Interrupt Status Reg
kFamrOffs_IER, // Interrupt Enable Reg
kFamrOffs_GPIODR, // GPIO Direction Reg
kFamrOffs_GPIOSR, // GPIO Status Reg
kFamrOffs_LEDR, // LED Reg
kFamrOffs_FPR, // Flash Page Reg => 0x9008_0018
kFamrOffs_RESERVED, // Reserved (19 - 1E)
kFamrOffs_FVR = kFpgaAmrOffs + 0xF // FPGA Version Reg => 0x9008_001F
};
И когда из программы-примера (того что в комплекте) пишу по адресу
0x90080017 своё значение, то светодиоды меняют своё состояние.
Соотвественно у меня такой вопрос как мне имея на руках адрес
полученный через ioremap(mmio_start, mmio_len) записать по адресу
0x90080017 своё значение в драйвере под Linux?