PCI Express设备驱动 (2)
#include "card.h"
#include <linux/time.h>
#include <linux/spinlock.h>
#define DMA_MASK 0xffffffff
#define test_dri_major 249 // 主设备号
//#define INT_ASSERT_W 0x02 // DMA Write Complete
//#define INT_ASSERT_R 0x10 // DMA Read Complete
/* PCI 驱动基本框架 */
static struct pci_device_id card_ids[] = {
{PCI_DEVICE(PCI_VENDOR_ID_XILINX,PCI_DEVICE_ID_EP_PIPE),},
{0,}
};
MODULE_DEVICE_TABLE(pci,card_ids);
static int card_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);
static void card_remove(struct pci_dev *pdev);
static struct pci_driver card_driver = {
.name = DEV_NAME,
.id_table = card_ids,
.probe = card_probe,
.remove = card_remove,
};
static int __init card_init(void)
{
int result;
result = pci_register_driver(&card_driver);
return result;
}
static void __exit card_exit(void)
{
pci_unregister_driver(&card_driver);
}
module_init(card_init);
module_exit(card_exit);
/* PCI 驱动基本框架 */
/* 特定设备私有数据结构 */
struct card_private {
struct pci_dev* pci_dev;
void* pci_bar0;
//wait_queue_head_t * dma_write_wait;
//wait_queue_head_t * dma_read_wait;
};
/* 特定设备私有数据结构 */
static struct card_private *adapter;
//static DECLARE_WAIT_QUEUE_HEAD(dma_write_wait);
//static int flag = 1;
// 将文件操作与分配的设备号相连
static const struct file_operations card_fops =
{
.owner = THIS_MODULE,
//.ioctl = card_ioctl,
.open = card_open,
.release= card_release,
.read = card_read,
.write = card_write,
};
static int card_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
unsigned long phymem;
void __iomem *mem;
u_int8_t csz;
u32 val;
int result;
if (pci_enable_device(pdev))
return -EIO;
/* XXX 32-bit addressing only */
if (pci_set_dma_mask(pdev, 0xffffffff)) {
printk(KERN_ERR "ath_pci: 32-bit DMA not available\n");
goto bad;
}
//pci_write_config_word(pdev, 0x04, 0x0007);
/*
* Cache line size is used to size and align various
* structures used to communicate with the hardware.
*/
pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
if (csz == 0) {
/*
* Linux 2.4.18 (at least) writes the cache line size
* register as a 16-bit wide register which is wrong.
* We must have this setup properly for rx buffer
* DMA to work so force a reasonable value here if it
* comes up zero.
*/
csz = L1_CACHE_BYTES / sizeof(u_int32_t);
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
}
/*
* The default setting of latency timer yields poor results,
* set it to the value used by other systems. It may be worth
* tweaking this setting more.
*/
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
pci_set_master(pdev);
/*
* Disable the RETRY_TIMEOUT register (0x41) to keep
* PCI Tx retries from interfering with C3 CPU state.
*
* Code taken from ipw2100 driver - jg
*/
pci_read_config_dword(pdev, 0x40, &val);
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
// 获得BAR0空间的基地址,该地址为存储器域的物理地址;
phymem = pci_resource_start(pdev, 0);
if (!request_mem_region(phymem, pci_resource_len(pdev, 0), DEV_NAME)) {
printk(KERN_ERR "card_driver: cannot reserve PCI memory region\n");
goto bad;
}
// 将存储器域的物理地址映射为虚拟地址;
mem = ioremap(phymem, pci_resource_len(pdev, 0));
if (!mem) {
printk(KERN_ERR "card_driver: cannot remap PCI memory region\n") ;
goto bad1;
}
adapter = kmalloc(sizeof(struct card_private), GFP_KERNEL);
if (unlikely(!adapter)){
return -ENOMEM;
}
adapter -> pci_dev = pdev;
adapter -> pci_bar0 = mem;
// 注册设备驱动程序
result = register_chrdev(test_dri_major, DEV_NAME, &card_fops);
if (unlikely(result)){
printk(KERN_ERR "card_driver: no memory for device state\n");
goto bad2;
}
/*
//init_waitqueue_head(adapter->dma_write_wait);
//init_waitqueue_head(adapter->dma_read_wait);
result = pci_enable_msi(pdev);
if (unlikely(result)){
//PDEBUG("cannot enable msi ... \n");
goto bad3;
}
result = request_irq(pdev -> irq, card_interrupt, 0, DEV_NAME, NULL);
if (unlikely(result)){
//PDEBUG("request interrupt failed ... \n");
goto bad3;
printk(KERN_DEBUG "request_irq(pdev -> irq, card_interrupt, 0, DEV_NAME, NULL);");
}
*/
return 0;
//bad3:
// unregister_chrdev(test_dri_major, DEV_NAME);
bad2:
iounmap(mem);
bad1:
release_mem_region(phymem, pci_resource_len(pdev, 0));
bad:
pci_disable_device(pdev);
return (-ENODEV);
}
static void card_remove(struct pci_dev *pdev)
{
//pci_disable_msi(pdev);
//if(pdev->irq)
// free_irq(pdev->irq, pdev);
iounmap(adapter -> pci_bar0);
release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
pci_disable_device(pdev);
unregister_chrdev(test_dri_major, DEV_NAME);
}