Sdio Drive (5) Sdio on the bus probe

Source: Internet
Author: User
Tags exception handling goto stack trace

Linux 2.6.38

The match success of driver and equipment on Sdio bus is just "incision" between software, like "return Money":

Liu Jinshan: When is the moon?

Feng Gong: Look up to yourself.

But Feng Gong didn't give him the money right away. Here hardware connectivity, can not work is not known, so to probe probe.

static int sdio_bus_probe (struct device *dev) {struct Sdio_driver *drv = To_sdio_driver (dev->driver);
	struct Sdio_func *func = dev_to_sdio_func (dev);
	const struct SDIO_DEVICE_ID *id;

	int ret;
	id = Sdio_match_device (func, DRV);

	if (!id) Return-enodev;
	 /* Unbound SDIO functions are always suspended.  * During probe, the function is set active and the usage count * is incremented. If the driver supports runtime PM, * It should call Pm_runtime_put_noidle () into its probe routine and * pm_runtime_get_
	 Noresume () in its remove routine.
		*/if (Func->card->host->caps & mmc_cap_power_off_card) {ret = Pm_runtime_get_sync (dev);
	if (Ret < 0) goto out; }/* Set the default block size so the driver is sure it ' s something * sensible.
	* * Sdio_claim_host (func);
	ret = sdio_set_block_size (func, 0);
	Sdio_release_host (func);

	if (ret) goto disable_runtimepm;
	ret = Drv->probe (func, id);

	if (ret) goto disable_runtimepm;

return 0; Disable_ruNtimepm:if (Func->card->host->caps & Mmc_cap_power_off_card) pm_runtime_put_noidle (dev);
Out:return ret; }
3, 4 lines are needless to say.

Line 8th to 10th, the previous match operation also called the Sdio_match_device, but at that time only concerned about whether the match, the other no matter. Here you need to use its sdio_device_id return value.


Line 12th to 22nd, the caps member of the SDIO host records its attributes (capability), and Mmc_cap_power_off_card is the option for Power Manager. The host setting this flag will turn off the card's power when suspend. Obviously, this is not allowed in the probe process, and the solution is to prevent the MMC subsystem from entering the suspend mode. The Pm_runtime_get_sync () call increases the reference count of the SDIO device, detects the reference count during the system suspend process, and then exits the suspend process by discovering that it is non-zero. Correspondingly, Pm_runtime_put_noidle () lowers the reference count, which means that they must be used in pairs.


Line 26th to 28th, set block size to do a good job in the protection and synchronization of the street resources, Sdio_claim_host exclusive (exclusively) occupy the host, after the use of the call Sdio_release_host to release. Controller as host, a host connected device (MMC subsystem known as card) more than one, so do a good synchronization is the point, such as Process 1 in the use of host to operate card A, process 1 work is not completed before Progress 2 can not use the host access card B; Of course, Process 1 After use to be released in a timely manner.

Implementation of exclusive access:

void Sdio_claim_host (struct sdio_func *func) {mmc_claim_host (func->card->host);}

static inline void Mmc_claim_host (struct mmc_host *host) {__mmc_claim_host (host, NULL); /** * __mmc_claim_host-exclusively claim a host * @host: MMC host to claim * @abort: Whether or not the Operation Sho  Uld is aborted * * Claim a host for a set of operations. If @abort is non null and * dereference a Non-zero value then this'll return prematurely with * that Non-zero value WI  Thout acquiring the lock.
 Returns Zero * With the lock held otherwise.
	* * int __mmc_claim_host (struct mmc_host *host, atomic_t *abort) {declare_waitqueue (wait, current);
	unsigned long flags;

	int stop;

	Might_sleep ();
	Add_wait_queue (&host->wq, &wait);
	Spin_lock_irqsave (&host->lock, flags);
		while (1) {set_current_state (task_uninterruptible); Stop = abort?
		Atomic_read (Abort): 0;
		if (Stop | |!host->claimed | | host->claimer = = current) break; Spin_unlock_irqrestoRe (&host->lock, flags);
		Schedule ();
	Spin_lock_irqsave (&host->lock, flags);
	} set_current_state (task_running);
		if (!stop) {host->claimed = 1;
		Host->claimer = current;
	HOST-&GT;CLAIM_CNT + 1;
	else Wake_up (&AMP;HOST-&GT;WQ);
	Spin_unlock_irqrestore (&host->lock, flags);
	Remove_wait_queue (&host->wq, &wait);
	if (!stop) mmc_host_enable (host);
return stop; }
Obviously the officer is __mmc_claim_host, and the second parameter is null.

23 Lines, Declare_waitqueue is a macro, and we expand it:

#define DECLARE_WAITQUEUE (name, tsk)					\
	wait_queue_t name = __waitqueue_initializer (name, tsk)
#define __ Waitqueue_initializer (name, tsk) {				\
	. Private	= tsk,						\
	. Func		= default_wake_function,			\
	. task_list	= {null, NULL}}

#define current (Get_current ())

declare_waitqueue (wait, current); c14/>wait_queue_t wait = {
	. Private = Get_current (),
	. Func		= default_wake_function,			\
	. Task _list	= {null, null}
}

This creates a waiting queue named "Wait" and initializes its members, setting its private member as the current process.

27 lines, Might_sleep () reminds the person using the code, this function may sleep. If in the atomic context (Spinlock, Irq-handler, ...) Call, this macro will print a stack trace, of course, opening the feature requires that the corresponding config be opened. There's not much to say here.

Line 29, Add_wait_queue (&HOST->WQ, &wait), add yourself ("Wait") to the waiting queue (HOST->WQ). Host->wq is already initialized in the Mmc_alloc_host () function mentioned in the Sdio driver (2) host registration process.

30 lines, Spin_lock_irqsave (&host->lock, flags), this spinlock performs three actions: Saves the current interrupt flag (to flag), disables CPU interrupts, obtains lock; natural Spin_unlock_ Irqrestore performs the opposite operation.

31~39 the while loop between rows, first setting the process state to task_uninterruptible, and then not responding to the signal, ensuring that the current process is not disturbed while waiting. The second argument passed in is null, so the stop equals 0. Then to judge, if we get the right to use the host to end the loop, otherwise resuming interrupts, releasing spinlock and scheduling, the current process into sleep waiting to wake up. Wake up under what circumstances. When another process release host:

static void Mmc_do_release_host (struct mmc_host *host)
{
	unsigned long flags;

	Spin_lock_irqsave (&host->lock, flags);
	if (--host->claim_cnt) {/
		* release for nested claim * *
		spin_unlock_irqrestore (&host->lock, flags); c6/>} else {
		host->claimed = 0;
		Host->claimer = NULL;
		Spin_unlock_irqrestore (&host->lock, flags);
		WAKE_UP (&HOST->WQ);
	}
It's clear, No.

The current process is awakened and set_current_state (task_running) continues to run.

The 41~45 line indicates that the host is occupied by the current process and increases the count.

46 Lines Remove wait queues, 50 exercise can host.


Now that we have ownership of host, Invoke Sdio_set_block_size to set the size of a block when communicating, the industry is called "Block size":

/** * Sdio_set_block_size-set The block size of a sdio function * @func: sdio function to change * @blksz: New block
 Size or 0 to use the default.  * * The default block size are the largest supported by both the function * and the host, with a maximum of
 This arbitrarily sized * data transfer use the optimal (least) number of commands. * A driver may call this to override the default block size set by the * core. This can is used to set a block size greater than the maximum * which reported by the card;
 It is the driver's responsibility to ensure * it uses a value of this card supports. * * Returns 0 on success,-einval if the "host does not support" * Requested block size, Or-eio (etc.) if one of the
 Resultant FBR block * Size Register writes failed.

	* * */int sdio_set_block_size (struct sdio_func *func, unsigned blksz) {int ret;

	if (Blksz > Func->card->host->max_blk_size) return-einval; if (Blksz = = 0) {blksz = min (func-> max_blksize, func->card->host->max_blk_size);
	Blksz = min (Blksz, 512u); ret = Mmc_io_rw_direct (func->card, 1, 0, sdio_fbr_base (func->num) + sdio_fbr_blksize, Blksz & 0xFF, NULL
	);
	if (ret) return ret; ret = Mmc_io_rw_direct (func->card, 1, 0, sdio_fbr_base (func->num) + sdio_fbr_blksize + 1, (Blksz >> 8) &am P
	0xFF, NULL);
	if (ret) return ret;
	Func->cur_blksize = Blksz;
return 0; }

It's necessary to say something about struct sdio_func. A SDIO card can support many functions, a function corresponds to the struct SDIO_FUNC structure on the software, and finally to the driver model is a device:

int Sdio_add_func (struct sdio_func *func)
{
	ret = Device_add (&func->dev);

	return ret;
}
The host obtains the number of functions supported by the card through CMD5, and the data is stored in response R4:


The card pointer member of the struct SDIO_FUNC represents the card type that the device belongs to. So 24 lines, if the parameter Blksz greater than the host specified maximum block size, return einval error.

27~30 Line, the second comment is clear that the setting of both sides (host and function device) supports the maximum block size.

32 lines, the emphasis is on mmc_io_rw_direct, we refer to its parametric analysis:

int mmc_io_rw_direct (struct mmc_card *card, int write, unsigned fn, unsigned addr, U8 in, U8 *out)
Card, corresponding to the external Sdio card, the card's host member on behalf of the cards connected to the host controller, host controller responsible for and the specific implementation of the cards communication.

Write, read and write logo, Sdio spec stipulates: 1 for write data to Sdio card, 0 for read data.

FN, function number, a SDIO card supports different functions, and these functions are numbered to be the function numbers here. Function number is represented by a 3 bit, which is the maximum of 7.

Here fn=0, open spec:note that function 0 selects the common I/O area (CIA) again. Cia-common I/O area:


addr, access address, accounting for 17 bit.

/
 * Function Basic registers (FBR)

/#define SDIO_FBR_BASE (f)	((f) * 0x100)/* BASE of function f ' s FBRS * *
#define SDIO_FBR_BLKSIZE	0x10	/* Block Size (2 bytes) * *
FBR of the CIA area:

Obviously, Sdio_fbr_base (func->num) + sdio_fbr_blksize = 0x100+0x10 = 0x110, is the lower 8-bit address of the FBR block size register, and 38 lines define a high 8-bit address.

In, the data written to the Sdio card is written two times.

Out, if we expect to get the Sdio card's response, the current state information of the card will be written to the out point location.

After two mmc_io_rw_direct () calls, the block size of the communication is set up, as to how the data is packaged, how it is sent, and how to obtain the response data see the construction and dispatch of the Sdio driver (6) command. Once set, synchronize block size to the Func->cur_blksize member of Line 42.


Then 32 lines, call the probe function of the Sdio driver, we use the WiFi-driven (1) framework to parse the RTL8723 mentioned in the example:

static struct Sdio_driver r871xs_drv = {
    . Probe = Rtw_drv_init,
    . remove = Rtw_dev_remove,
    . Name = (char*) drv_ NAME,
    . id_table = Sdio_ids,
};

static int rtw_drv_entry (void)
{
    ret = sdio_register_driver (&r871xs_drv);
    return ret;
}
Then the Rtw_drv_init function is invoked.


Finally 33~42 line, exception handling before all mentioned, no accident words the whole probe end, over.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.