Driven:
Taking Sdio as an example, it uses Mmc_attach_sdio to match the driver and the device, and its essence is to match the Sdio_bus matching rules. In Mmc_attach_sdio, the MMC first matches a bus, that is, what bus to use for the MMC bus to process host. One thing to understand here is that in Sdio, for SD card memory MMC is a physical device, and for non-SD card memory, such as the Sdio interface device, the MMC is characterized as bus, this is more important. There are sdio_bus in addition to MMC BUS.
/*
* Starting point for SDIO card init.
*/
int Mmc_attach_sdio (struct mmc_host *host)
{
int err, I, funcs;
U32 OCR;
struct Mmc_card *card;
BUG_ON (!host);
WARN_ON (!host->claimed);
Err = Mmc_send_io_op_cond (host, 0, &OCR);
if (ERR)
return err;
Mmc_attach_bus (host, &mmc_sdio_ops);
if (Host->ocr_avail_sdio)
Host->ocr_avail = host->ocr_avail_sdio;
/*
* Sanity Check the voltages the card claims to
* Support.
*/
if (OCR & 0x7F) {
Pr_warning ("%s:card claims to support voltages"
"below the defined range. These'll be ignored.\n ",
Mmc_hostname (host));
OCR &= ~0x7f;
}
HOST->OCR = Mmc_select_voltage (host, OCR);
/*
* Can We support the voltage (s) of the card (s)?
*/
if (!HOST->OCR) {
err =-einval;
Goto err;
}
/*
* Detect and init the card.
*/
Err = Mmc_sdio_init_card (host, HOST->OCR, NULL, 0);
if (err) {
if (err = =-eagain) {
/*
* Retry initialization with S18R set to 0.
*/
HOST->OCR &= ~r4_18v_present;
Err = Mmc_sdio_init_card (host, HOST->OCR, NULL, 0);
}
if (ERR)
Goto err;
}
Card = host->card;
/*
* Enable runtime PM only if supported by Host+card+board
*/
if (Host->caps & Mmc_cap_power_off_card) {
/*
* Let runtime PM core know we card is active
*/
Err = pm_runtime_set_active (&card->dev);
if (ERR)
Goto Remove;
/*
* Enable Runtime PM for this card
*/
Pm_runtime_enable (&card->dev);
}
/*
* The number of functions on the card is encoded inside
* The OCR.
*/
Funcs = (OCR & 0x70000000) >> 28;
Card->sdio_funcs = 0;
#ifdef Config_mmc_embedded_sdio
if (Host->embedded_sdio_data.funcs)
Card->sdio_funcs = Funcs = host->embedded_sdio_data.num_funcs;
#endif
/*
* Initialize (but don ' t add) all present functions.
*/
for (i = 0; i < Funcs; i++, card->sdio_funcs++) {
#ifdef Config_mmc_embedded_sdio
if (Host->embedded_sdio_data.funcs) {
struct Sdio_func *tmp;
TMP = Sdio_alloc_func (Host->card);
if (Is_err (TMP))
Goto Remove;
Tmp->num = (i + 1);
Card->sdio_func[i] = tmp;
Tmp->class = host->embedded_sdio_data.funcs[i].f_class;
Tmp->max_blksize = host->embedded_sdio_data.funcs[i].f_maxblksize;
Tmp->vendor = card->cis.vendor;
Tmp->device = card->cis.device;
} else {
#endif
Err = Sdio_init_func (Host->card, i + 1);
if (ERR)
Goto Remove;
#ifdef Config_mmc_embedded_sdio
}
#endif
/*
* Enable Runtime PM for this func (if supported)
*/
if (Host->caps & Mmc_cap_power_off_card)
Pm_runtime_enable (&card->sdio_func[i]->dev);
}
/*
* First add the card to the driver model ...
*/
Mmc_release_host (host);
Err = Mmc_add_card (Host->card);
if (ERR)
Goto remove_added;
/*
* ... then the SDIO functions.
*/
for (i = 0;i < funcs;i++) {
Err = Sdio_add_func (Host->card->sdio_func[i]);
if (ERR)
Goto remove_added;
}
Mmc_claim_host (host);
return 0;
Remove_added:
/* Remove without lock if the device has been added. */
Mmc_sdio_remove (host);
Mmc_claim_host (host);
Remove
/* And with lock if it hasn ' t been added. */
Mmc_release_host (host);
if (Host->card)
Mmc_sdio_remove (host);
Mmc_claim_host (host);
Err:
Mmc_detach_bus (host);
Pr_err ("%s:error%d whilst initialising SDIO card\n",
Mmc_hostname (host), err);
return err;
}
More difficult to understand is the func, which is actually a physical device package, it can be considered a device.
/*
* Allocate and initialise a new SDIO function structure.
*/
struct Sdio_func *sdio_alloc_func (struct Mmc_card *card)
{
struct Sdio_func *func;
Func = kzalloc (sizeof (struct sdio_func), gfp_kernel);
if (!func)
Return Err_ptr (-ENOMEM);
Func->card = Card;
Device_initialize (&func->dev);
Func->dev.parent = &card->dev;//Card device is the parent device of the SDIO device.
Func->dev.bus = &sdio_bus_type;
Func->dev.release = Sdio_release_func;
return func;
}
The above code at a glance, which is the specific device entity encapsulation, the bus type is Sdio_bus. Sdio_init_func only Initializes a device, and there is no register. In the Sdio_add_func implementation of the device register, the same is the card entity, before the Mmc_add_card is not registered, in the Mmc_add_card function to realize the registration of the device.
To this device registration is completed, in fact, Sdio bus in the form similar to the USB bus, why? Children's shoes have been written USB drive should know, write USB driver is only to write driver loading, and do not specifically load device entities, resulting in many children's shoes confusion, why no device loading, in fact, when the USB device is inserted, will dynamically create a USB device entity, after the USB device entity creation is completed, The matching driver is called according to the different device IDs. and Sdio equipment is the same. The code above is confusing, and always makes it difficult to see the loading of specific devices. In fact, in the code above, it includes the driver of the MMC host.
Linux Sdio bus driver (ii)