include/linux/mod_devicetable.h
#ifdef __KERNEL__
#include <linux/types.h>
typedef unsigned long kernel_ulong_t;
#endif
#define PCI_ANY_ID (~0)
struct pci_device_id {
__u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
__u32 class, class_mask; /* (class,subclass,prog-if) triplet */
kernel_ulong_t driver_data; /* Data private to the driver */
};
===========================================================
device/mmc/host/sdhci-pci.c
static const struct pci_device_id pci_ids[] __devinitdata = {
{
.vendor = PCI_VENDOR_ID_RICOH,
.device = PCI_DEVICE_ID_RICOH_R5C822,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_ricoh,
},
static struct pci_driver sdhci_driver = {
.name = "sdhci-pci",
.id_table = pci_ids,
.probe = sdhci_pci_probe,
.remove = __devexit_p(sdhci_pci_remove),
.driver = {
.pm = &sdhci_pci_pm_ops
},
};
============================================================
include/linux/pci_ids.h定义了vendor和device的ID。
#define PCI_VENDOR_ID_RICOH 0x1180
#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466
#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475
#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476
#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478
#define PCI_DEVICE_ID_RICOH_R5C822 0x0822
#define PCI_DEVICE_ID_RICOH_R5CE823 0xe823
#define PCI_DEVICE_ID_RICOH_R5C832 0x0832
#define PCI_DEVICE_ID_RICOH_R5C843 0x0843
=============================================================================
struct sdhci_pci_chip {
struct pci_dev *pdev;
unsigned int quirks;
unsigned int quirks2;
bool allow_runtime_pm;
const struct sdhci_pci_fixes *fixes;
int num_slots; /* Slots on controller */
struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */
};
======
static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot()device探测函数。
1. 从PCI配置空间中0x40处读取SLOT 信息。
其中bit[0-2]是first bar address register number;
bit[4-6]slot的个数。
2. 接下来激活这个设备 pci_enable_device().
3. 申请一段内存给struct sdhci_pci_chip;并给其pci_dev 赋值。chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
if (chip->fixes) {
chip->quirks = chip->fixes->quirks;
chip->quirks2 = chip->fixes->quirks2;
chip->allow_runtime_pm = chip->fixes->allow_runtime_pm;
}
这个是各个pci不同设备特有的,每个都不同。
chip->num_slots = slots;
pci_set_drvdata(pdev, chip);
chip->fixes->probe(chip);
slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
chip->slots[i] = slot;
=====================================================
static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot()
1. struct sdhci_host *host;
host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));
2. slot = sdhci_priv(host);
slot->chip = chip;
slot->host = host;
slot->pci_bar = bar;
slot->rst_n_gpio = -EINVAL;
slot->cd_gpio = -EINVAL;
3. host->hw_name = "PCI";
host->ops = &sdhci_pci_ops;
host->quirks = chip->quirks;
host->quirks2 = chip->quirks2;
host->irq = pdev->irq; //host controller 中断获取
ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc)); //region IO port by request_region();
host->ioaddr = pci_ioremap_bar(pdev, bar); //map io memory.
if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
gpio_direction_output(slot->rst_n_gpio, 1);
slot->host->mmc->caps |= MMC_CAP_HW_RESET;
ret = sdhci_add_host(host);
sdhci_pci_add_own_cd(slot);
====================================
static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
{
struct sdhci_pci_slot *slot = dev_id;
struct sdhci_host *host = slot->host;
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
return IRQ_HANDLED;
}
static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
{
int err, irq, gpio = slot->cd_gpio;
slot->cd_gpio = -EINVAL;
slot->cd_irq = -EINVAL;
if (!gpio_is_valid(gpio))
return;
err = gpio_request(gpio, "sd_cd");
if (err < 0)
goto out;
err = gpio_direction_input(gpio);
if (err < 0)
goto out_free;
irq = gpio_to_irq(gpio);
if (irq < 0)
goto out_free;
err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING, "sd_cd", slot);
if (err)
goto out_free;
slot->cd_gpio = gpio;
slot->cd_irq = irq;
return;
out_free:
gpio_free(gpio);
out:
dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
}
===========================================================
struct sdhci_pci_slot {
struct sdhci_pci_chip *chip;
struct sdhci_host *host;
struct sdhci_pci_data *data;
int pci_bar;
int rst_n_gpio; //putput pin to reset eMMC
int cd_gpio; //input pin to detect card inset/remove
int cd_irq; //gpio pin to irq num
};
The ops is sdhci_host ops:
static struct sdhci_ops sdhci_pci_ops = {
.enable_dma = sdhci_pci_enable_dma,
.platform_8bit_width = sdhci_pci_8bit_width,
.hw_reset = sdhci_pci_hw_reset,
};