Share this

Research on MMC Card Driver Management Technology in Embedded Linux Systems

2026-04-06 03:30:34 · · #1
[Abstract] This paper briefly introduces the architecture of MMC card drivers, designs and implements the low-level driver for MMC cards, improves upon the single-block read/write functionality of traditional block device drivers to achieve clustered read/write of MMC cards, and implements power management and plug-and-play functionality. [Keywords] Linux, MMC card, low-level driver, clustered read/write, hot- swap. Introduction MMC (Multimedia Card) is a small, high-capacity, and easy-to-use memory widely used in embedded systems such as mobile phones. MMC controls and manages the card through an integrated on-chip controller. Once the host correctly drives the MMC card, it can access data as easily as a hard disk. The Linux driver studied and implemented in this paper uses the Intel XScale PXA250 as the hardware platform. Based on the MMC card communication protocol specification, it implements low-level read/write functionality. Then, it improves upon the single-block read/write functionality of traditional block device drivers to achieve clustered read/write technology, improving the card's read/write speed; it also adds power management functionality to meet the low-power requirements of embedded systems; and it adds plug-and-play functionality for user convenience. 1. MMC Card Driver Architecture The MMC card connects to the host controller via only 5 pins and communicates with the host through a serial protocol. The simple hardware structure of the MMC card inevitably leads to complexity in driver implementation. Based on the MMC card communication protocol specification and the structure of Linux drivers, the original low-level driver, daemon thread, and single-block read/write functionality of the driver are improved and extended. The structure is further divided into five parts: low-level driver, daemon thread, cluster read/write, power management, and hot-swap management, as shown in Figure 1. The functions of each part in Figure 1 are as follows: ① Low-level driver – Handles operations directly involving the MMC card's hardware register ports, including command issuance and response, interrupt response and handling, PIO or DMA channel data transfer, etc. ② Cluster read/write – Merges read/write requests for adjacent data blocks on the disk and issues read/write commands together to accelerate data reading and writing, and implements concurrent control during reading and writing. ③ Power management – ​​Implements low-power management of the MMC card. ④ Hot-swap management – ​​Implements plug-and-play functionality for the MMC card. ⑤ Daemon thread – Responds to file system read/write requests and initiates I/O to the card. 2 Implementation of MMC Card Driver 2.1 Low-level Driver The low-level driver refers to the direct operation of the MMC card. The MMC card adopts a serial data transmission method; it is a relatively "refined" card, and its operation is relatively complex and requires accurate timing. The following describes how to perform low-level read and write driver from three aspects: command issuance and response, interrupt response and handling, and DMA data transmission. (1) Command Issuance and Response The operation of the MMC card is achieved by reading and writing its 18 control registers. First, set the lowest two bits of the clock start/stop register MMC_STRCPL to 01 to turn off the internal clock of the MMC card. Then, set the lowest 7 bits of the interrupt mask register MMC_LMASK to 1 to mask all interrupts to the MMC controller, and then write command parameters to the specified MMC control register, such as the clock frequency setting register MMC_CLKRT, the read/write block count register MMC_NOB, the command register MMC_CMD, etc. Finally, turn on the internal clock and unmask the interrupts. At this time, the current read/write process enters a sleep state, waiting for the interrupt handler to wake it up. (2) Interrupt Response and Handling The MMC card generates interrupts upon data transfer request, internal clock shutdown, command issuance completion, and data transfer completion. However, the MMC card controller is only connected to the CPU via a single GPIO23 pin for interrupt signal line multiplexing. Therefore, the interrupt handler must first determine the cause of the interrupt before proceeding with the appropriate handling. Here, after the MMC card correctly issues a read/write command, the system generates one interrupt. The interrupt handler reads the value of MMC_IREG to determine if the command has been successfully issued and wakes up the process waiting for the command to complete. After being woken up by the interrupt, the read/write process first reads the status information in the MMC card response register MMC_RES, and then determines whether the command was successfully issued and the current status of the card based on this status information. If the status information indicates that the command was successfully executed, data is read and written through the read/write buffer registers MMC_RXFIFO and MMC_TXFIFO (DMA is used for data transfer here to improve data transfer speed); if the returned status information indicates that the command was not successfully executed, the corresponding error handling is performed based on the status information. (3) Data reading and writing of the MMC card in the DMA data transfer driver are performed through the DMA channel. In order to ensure the continuity of operation, the driver sets up one DMA channel for the input and output buffers of the MMC card. During actual data transfer, the read and write process also enters a sleep state and is awakened by the DMA interrupt after the DMA data transfer is completed. The pseudocode for implementing a single read operation is as follows: Pxa_read_mmc() { Turn off the clock and disable interrupts; Set the contents of the read/write registers; /* Number of read/write blocks, starting block number, read/write speed, etc. */ Turn on the clock and issue read/write commands; Interruptible_sleep_on(); /* Enter interruptible sleep state and wait for the interrupt routine to wake it up */ Wake up by the interrupt routine, open the DMA channel, perform data transfer, and enter the interruptible sleep state again; Wake up by the interrupt after DMA transfer is completed, issue the end transfer command, and end the data transfer; 2.2 Clustering Read/Write and Concurrency Control 2.2.1 Traditional Block Device Driver Structure and Insufficient Block Device Drivers are among the most complex drivers in the Linux system. Refer to references [3, 4] for a detailed understanding of Linux block device drivers. Here, we briefly introduce the data structures and operations related to clustering read/write. A sector is the basic unit for data transfer in block device hardware, while a block is a group of adjacent sectors involved in a block device request for one I/O operation. Each block needs its own memory buffer. The buffer head is a data structure associated with each buffer. Every I/O transfer on a block device must pass through the block's buffer. Linux block device drivers employ a delayed I/O strategy. When a process has an I/O request, the driver delays for a period, associates consecutive buffer head structures on the block device together to form an I/O request descriptor (struct request), and then queues the request structure into the device's request queue (request_queue_t) using an elevator algorithm. Thus, during actual I/O transfers, the corresponding block device request queues are processed sequentially. The elevator queuing algorithm for the request structure avoids performance degradation caused by frequent head movements. However, currently in Linux block device drivers, issuing I/O read/write commands separately for each buffer head structure within a request structure causes the read/write head to pause for a period of time each time an input/output occurs to a buffer head, performing DMA data read/write. This frequent head start-stop leads to disk performance degradation. 2.2.2 Implementation of Clustered Read/Write Traditional block device drivers buffer only one buffer_head per read/write command, leading to performance degradation. To address this issue, we improved the traditional block device driver by implementing clustered read/write. Since the physical blocks corresponding to the buffer_head structures of each request structure are adjacent, this creates the conditions for clustered read/write. The `nr_sectors` in the request structure represents the number of blocks that the request structure needs to read/write. During read/write operations, `nr_sectors` blocks are issued at once, reading the block device content into the memory area corresponding to the first buffer_head structure pointed to by the request structure. When a buffer_head structure's buffer is full, the read/write buffer address is adjusted to the buffer pointed to by the next buffer_head, and DMA is used for data transfer to improve read/write speed. After completing the operation on a request structure, the request structure resources are released. The pseudocode for implementing cluster read operations is as follows: `Read_mmc() { Issue read/write commands, reading data blocks equal to the number of blocks in one `rcquest` > `nr_sectors`; The buffer pointer points to the buffer pointed to by the first `bh` structure; while (data not yet read) { Read data into the buffer specified by the `buffer_head` structure; /* Call `Pxa_read_mmc()` */ Adjust the buffer pointer to the buffer pointed to by the next `buffer_head` structure; } }` 2.2.3 Concurrency Control in Cluster Read/Write If the I/O request queue `request_queue_t` is accessed in many places in the kernel, then the queue becomes a critical resource. To protect this queue from mutual exclusion, all request queues in Linux 2.4 are protected by a single global spinlock `io_request_lock`. All operations on the request queue must hold this lock and be interrupt-free. However, while the driver holds this lock, no other read/write requests can be queued to any block device in the system, and other read/write processing functions cannot run. To minimize the performance degradation caused by the driver holding the lock for an extended period, the following principles must be followed when implementing clustered read/write operations: ① The lock must be acquired before performing read/write operations on the request queue; ② The request lock must be released after the operation on the request queue is completed; ③ To reduce the time the lock is held, the request structure can be removed from the queue first, then the lock can be released, and then the removed request structure can be operated on while the lock is released. Based on the above principles, the pseudocode of the read/write processing function is as follows: mmc_request_fn() whilc(1) { Lock io_request_lock; Read the first request structure request in the current MMC card request queue; Release the lock io_request_lock; if (request is empty) cxit(O); /* No queue to process, return */ read_mmc(); /* Call the cluster read/write function */ Lock io_request_lock; Retrieve the processed request structure from the queue structure and release the request resource; Release the lock io_request_lock; } } 2.3 Daemon Thread When the MMC card driver is initialized, the daemon thread mme_block_thread is started. It is usually in a sleep state. When there is a read/write request for the MMC card, mmc_block_thread is awakened. The thread calls the above read/write processing function mmc_request_fn(), processes it, and then enters a sleep state. 2.4 Power Management Embedded systems generally have low power consumption requirements. When a device has been idle for an extended period, power should be cut off to reduce energy consumption. The kernel maintains a queue of registered power management devices called `pm_list`, along with a power management thread called `kpowered`, which has the lowest priority among all running processes. When no processes are running for a long time, `kpowered` is awakened and scans the `pm_list` queue for each registered device. If a device has been idle for an extended period, a `PM_SUSPEND` event is sent to it; when the device is restarted, a `PM_RESUME` event is sent to the `pm_list` queue. The power management callback function `mme_block_callback`, i.e., `pm_register(PM_UNKNOWN_DEV, 0, mme_pm_callback)`, is registered in the MMC card driver module. This registers the MMC card in the `pm_list` queue. When a power event occurs, the `mmc_pm_callback` function is triggered. This function handles various power events. There are two types of power events in the program: ① `PM_SUSPEND` event. This event causes the MMC card to enter power-saving mode. At this time, the driver saves the current state of the MMC card and the contents of important registers, such as the clock register MMC_CLKRT and the status register MMC_STAT. Then, it sets the power supply GPIO of the MMC card to high level, shutting off the power supply to the MMC card, and sets the corresponding bit in the clock enable register CKEN of the MMC card to 0, disabling the clock pulse of the MMC card. At this time, the MMC card enters power-saving mode. ②PM_RESUME event. This event causes the MMC card to enter normal operating mode. At this time, the program restores the registers saved before entering power-saving mode, turns on the power supply and clock pulse, and the MMC card returns to normal operating mode. Of course, power events can also be voluntarily triggered by the user process. A power management interface is provided in the file system interface file_operation io_control, and users can send power event requests to the card through io_control. 2.5 Hot-plug management In embedded systems such as mobile phones and PDAs, plug-and-play functionality is required, allowing users to use the device immediately without installing drivers. Linux handles hot-plug events at both the system and application layers. At the system layer, it detects MMC card hot-plug events, allocates or releases system resources, and drives the MMC card. Simultaneously, it accurately and promptly notifies the application layer of these events, allowing the application layer to process them accordingly. At the operating system layer, a character device file named `mmc_plug` needs to be registered for the application layer to detect MMC card hot-plug events. The CPU connects to the MMC card via GPIO12 for interrupt detection of card insertion/removal. Simultaneously, the driver sets a semaphore `MMC_EVENT`, which takes the values ​​`MMC_INSERT` and `MMC_REMOVAL`. When the card is inserted or removed, these values ​​are set to `MMC_INSERT` and `MMC_REMOVAL` respectively in the interrupt handler and simultaneously passed to the character device `mmc_plug` for use by upper-layer applications. To enable the application layer to be aware of card insertion/removal events, an asynchronous I/O mechanism, poll, is used on the character device `mmc_plug`. Processes that need to receive kernel insertion/removal events sleep in a waiting queue via poll. When a card insertion/removal event occurs, an interrupt is generated, and the interrupt handler wakes up the waiting process in the queue. After being woken up, the upper-layer process reads the character device to obtain the event. At the application layer, processes listen for hot-plug events of the MMC card using the select mechanism. When no insertion/removal events occur, the process enters a blocked state, relinquishing CPU resources. When a hot-plug event occurs, the system wakes up the process added to the waiting queue via poll, and the application layer obtains the MMC card hot-plug event through the read function and performs corresponding application-level processing. Of course, the application layer can also notify the system layer to process the card using the write method. Conclusion This paper studies and implements an MMC card driver program. Its cluster read/write implementation demonstrates stable and high read/write speeds. Power management functions are added, reducing power consumption and meeting the low-power requirements of embedded systems. The added plug-and-play functionality greatly facilitates user operation. The driver architecture is a good way to implement block device drivers for embedded systems.
Read next

CATDOLL Tami Hybrid Silicone Head

The hybrid silicone head is crafted using a soft silicone base combined with a reinforced scalp section, allowing durab...

Articles 2026-02-22