Opção 1 (acesso direto via / sys /.../ resource0)
Bom para testes e nada de errado com isso funcionalmente, embora não possa fazer nada avançado e sem abstração de camada de driver. Eu acho esse método nojento pela forma como o programa do usuário interage com o sysfs, mas essa pode ser minha opinião pessoal.
Opção 2 (usando uio_pci_generic)
Eu não sei o que o uio_pci_generic faz, mas parece adicionar pouca funcionalidade além de permitir que o seu programa de usuário acesse interrupções herdadas do pci. O que é ruim porque a MSI é preferida de qualquer maneira.
Opção 3 (driver uio personalizado)
Eu não tentei isso, mas suspeito que seja um desperdício de tempo em comparação com a opção 4
Opção 4 (driver de kernel personalizado)
Esta é realmente a melhor solução e a única maneira de fazer as coisas corretamente. Você precisa de um driver para ser capaz de lidar com coisas como DMA e MSI corretamente e ser capaz de fornecer qualquer quantidade de abstração através de um dispositivo de caracteres. No entanto, há ampla documentação sobre como escrever drivers para placas PCI on-line e o kernel fornece muito suporte para o gerenciamento de coisas.