嵌入式技术
下面的总线都属于 PCI 族:
这些技术都是互相兼容的,内核驱动可以使用同一套。内核不需要感知硬件到底用的是什么插槽和总线变种。
PCI 总线上的设备类型主要有:
主要是针对设备驱动开发者。
这些偏移的定义,在内核的 include/linux/pci_regs.h。
drivers/net/ne2k-pci.c:
static struct pci_device_id ne2k_pci_tbl[] = {
{ 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 },
{ 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 },
{ 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 },
{ 0x8e2e, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_KTI_ET32P2 },
{ 0x4a14, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_NetVin_NV5000SC },
{ 0x1106, 0x0926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Via_86C926 },
{ 0x10bd, 0x0e34, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_SureCom_NE34 },
{ 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F },
{ 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 },
{ 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 },
{ 0x8c4a, 0x1980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940_8c4a },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl);
注册驱动的操作函数,以及驱动所支持的设备表:
static struct pci_driver ne2k_driver = {
.name = DRV_NAME,
.probe = ne2k_pci_init_one,
.remove = __devexit_p(ne2k_pci_remove_one),
.id_table = ne2k_pci_tbl,
#ifdef CONFIG_PM
.suspend = ne2k_pci_suspend,
.resume = ne2k_pci_resume,
#endif /* CONFIG_PM */
};
static int __init ne2k_pci_init(void)
{
return pci_register_driver(&ne2k_driver);
}
static void __exit ne2k_pci_cleanup(void)
{
pci_unregister_driver (&ne2k_driver);
}
示例:
static struct pci_driver ne2k_driver = {
.name = DRV_NAME,
.probe = ne2k_pci_init_one,
.remove = __devexit_p(ne2k_pci_remove_one),
.id_table = ne2k_pci_tbl,
...
};
pci_enable_device() 可能会失败,所以需要检查其返回值!
pci_enable_device(drivers/net/ne2k-pci.c)示例:
static int __devinit ne2k_pci_init_one
(struct pci_dev *pdev, const struct pci_device_id *ent)
{
...
i = pci_enable_device (pdev);
if (i)
return i;
...
}
访问 I/O 内存和端口信息。
#include < linux/pci.h >
/* 读接口 */
int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
int pci_read_config_word(struct pci_dev *dev, int where, u16 *val);
int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val);
/* 读示例:drivers/net/cassini.c */
pci_read_config_word(cp >pdev, PCI_STATUS, &cfg);
/* 写接口 */
int pci_write_config_byte(struct pci_dev *dev, int where, u8 val);
int pci_write_config_word(struct pci_dev *dev, int where, u16 val);
int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
/* 写示例:drivers/net/s2io.c */
/* Clear "detected parity error" bit
pci_write_config_word(sp >pdev, PCI_STATUS, 0x8000);
#include < linux/pci.h >
long iobase = pci_resource_start(pdev, bar);
long iosize = pci_resource_len(pdev, bar);
request_region(iobase, iosize, “my driver”);
或者简单点:
pci_request_region(pdev, bar, “my driver”);
或者更简单点:
pci_request_regions(pdev, “my driver”);
示例代码(drivers/net/ne2k-pci.c):
ioaddr = pci_resource_start (pdev, 0);
irq = pdev- >irq;
if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0))
{
dev_err(&pdev- >dev, "no I/O resource at PCI BAR #0\\n");
return -ENODEV;
}
if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
dev_err(&pdev- >dev, "I/O resource 0x%x @ 0x%lx busy\\n", NE_IO_EXTENT, ioaddr);
return -EBUSY;
}
示例(drivers/net/wireless/ipw2200.c):
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (!err)
err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\\n");
goto out_pci_disable_device;
}
至此,已完成 DMA mask size 的分配。
如果设备需要的话:
示例:清除 pending 的中断。
在 remove() 函数中,你通常需要对在设备初始化(probe() 函数)中所做工作进行逆操作:
全部0条评论
快来发表一下你的评论吧 !