?? usr_blk_dev.c
字號:
/* * Copyright 2005 Motorola, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307, USA * *//*! * @file usr_blk_dev.c * * @ingroup usr_blk_dev * * @brief This is the main file for the user block driver. * * <B>Overview:</B><BR> * The user block driver is a removable media block driver intended to allow * for user space drivers for the media. * * This driver operates by creating an entry on /proc and using the entry * to communicate commands to user space. See ::USR_BLK_DEV_CMD_ID_T for a list * of these commands. Commands are sent from a kernel thread through /proc * to user space. Once the user space process has completed the command it * responds with a write to the proc entry. Only one command can be processed * at a time by a user space process and a kernel thread. A thread is used * for the commands in order to keep the request queue from blocking which is * not allowed. * * At this time a single thread is used for all devices attached. This * is not intended to be the final design, but was done to speed up development. * This will be acceptable for systems which implement only one device. If * more than one device is to be supported, then multiple threads should be * used, one per /proc entry. This will speed up throughput, since one part * will not block the others. * * There are two different levels of command processing within this driver. * Commands from interrupts, the request queue and general file operations * (open, revalidate, check_media) are placed in the command structure * (usr_blk_dev_cmd_s) within the information structure (::USR_BLK_DEV_INFO_T) * for the device. These commands are then processed by the kernel thread * (usr_blk_dev_thread()) and sent to user space. Once they are processed by * user space, the kernel thread copies any return data and informs the source * of the command that it has been completed. * * Part detection is done via a switch in the socket which is connected to * GPIO on the part. An interrupt is generated on both the rising edge and the * falling edge of the signal. Once an interrupt is detected a timer is used * do debounce the signal. After the signal has achieved a steady state the * interrupt is re-enabled and the timer stopped. * * <B>Devices Created:</B><BR> * -# /proc/usr_blk_dev0: The read/write interface to the user space driver * for device 0. * -# /proc/usr_blk_devn: The read/write interface to the user space driver * for device n. * <B>Devices Used:</B><BR> * -# /dev/mmca0: The root for the first detected card in the first slot. * -# /dev/mmca\<n\>: The partitions of the detected card (up to 8 partitions * are supported). * -# /dev/mmcb0: The root for the card in the second slot if detected. * Additional cards continue to increment the letter (c, d, e, ...). * -# /dev/mmcb\<n\>: The partitions of the card in the second slot. * Additional cards continue to increment the letter (c, d, e, ...). * * <B>Command Lifecycle:</B><BR> * When a command is sent to the user block thread it transitions through * the states described in ::USR_BLK_DEV_CMD_STATE_T. As they enter a new * state they may wait on a wait queue or wake up another queue as they * complete. It is necessary for commands to cycle through the states or * they can hold up all subsequent commands. * * The following describes the states and the wait queues used within them. * The state for the commands are stored in * usr_blk_dev_info[dev_num].cmd[cmd_src].state * * <B>#USR_BLK_DEV_CMD_STATE_NONE:</B><BR> * This state can be considered the idle state of the driver. This value sits * in the state variable when the no command is active. A transition to the * ::USR_BLK_DEV_CMD_STATE_NEW state starts a command executing in the user block * thread.<BR> * * <B>#USR_BLK_DEV_CMD_STATE_NEW:</B><BR> * This is the state a requester must put in the state value in order to start * a command executing. In the case of commands which come from locations which * can block the wait queue usr_blk_dev_info[dev_num].cmd[cmd_src].wait_for_completion * must be used before the new command can be added. * * <B>#USR_BLK_DEV_CMD_STATE_THREAD:</B><BR> * This value is placed in the state control variable as soon as the user block * thread detects the command is new. It does not wait on any queues. * * <B>#USR_BLK_DEV_CMD_STATE_USR_READ</B><BR> * When a command is in this state it has woken up the * usr_blk_dev_info[dev_num].wait_for_usr_read queue which controls when user * reads of the /proc entry happen. * * <B>#USR_BLK_DEV_CMD_STATE_USR_WAIT:</B><BR> * This state is transitioned to as soon as the user process reads the command * from the /proc entry. The command will remain in this state until the * response is written to the /proc entry from the user driver. Commands in * this state (as well as the ::USR_BLK_DEV_CMD_STATE_USR_READ) are waiting on * the usr_blk_dev_info[dev_num].wait_for_usr_write queue. * * <B>#USR_BLK_DEV_CMD_STATE_USR_DONE:</B><BR> * This state is entered as soon as the usr_blk_dev_info[dev_num].wait_for_usr_write * queue is awakened. At this point the user block thread continues by processing * any necessary data. If the data was from the request queue * (::USR_BLK_DEV_CMD_SRC_REQ) or an interrupt (::USR_BLK_DEV_CMD_SRC_IRQ) the command * is transitioned to ::USR_BLK_DEV_CMD_STATE_NONE since no more processing is * necessary. If it is not from one of these sources it will wake up the * usr_blk_dev_info[dev_num].cmd[cmd_src].wait_for_thread queue to allow the * requester to process the data. * * <B>#USR_BLK_DEV_CMD_STATE_THREAD_DONE:</B><BR> * Once the user block thread is done executing a command the * usr_blk_dev_info[dev_num].cmd[cmd_src].wait_for_thread will be awakened and the * requester of the command will transition to this state. Within this state * the requester will act upon the date returned and set the state back to * #USR_BLK_DEV_CMD_STATE_NONE. * * For more data on the individual commands see the ::USR_BLK_DEV_CMD_ID_T. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <stdbool.h>#include <asm/arch/hardware.h>#include <linux/blk.h>#include <linux/blkdev.h>#include <linux/blkpg.h>#include <linux/fs.h>#include <linux/genhd.h>#include <linux/hdreg.h>#include <linux/init.h>#include <asm/irq.h>#include <linux/proc_fs.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/timer.h>#include <asm/uaccess.h>#include <linux/wait.h>#include <linux/usr_blk_dev.h>/******************************************************************************* Local constants and macros******************************************************************************//*! * @brief The number of successive times the sample of the device attach signal must * match before the device state is changed. */#define USR_BLK_DEV_DEBOUNCE_CNT 4#ifndef CONFIG_ARCH_SCMA11/*! @brief Port to which the media card detect switch is attached. */#define USR_BLK_DEV_DEV1_INT_GPIO 11 /*! @brief Returns non zero if the media card is attached. */# define USR_BLK_DEV_IS_DEV1_ATTACHED ((GPLR(USR_BLK_DEV_DEV1_INT_GPIO) & GPIO_bit(USR_BLK_DEV_DEV1_INT_GPIO)) != 0)#endif/*! @brief The name of the /proc entry as it will appear in the directory /proc. */#define USR_BLK_DEV_PROC_ENTRY_STR "usr_blk_dev"/*! @brief The number of characters in USR_BLK_DEV_PROC_ENTRY_STR. */#define USR_BLK_DEV_PROC_ENTRY_LEN 11/*! * @brief The number of times the proc entry for a device can be opened. * * The number of times the proc entry for a device can be opened. This is set * to one since only one user driver is needed to drive a device and if more * than one user process opens the entry, bad things would happen. */#define USR_BLK_DEV_MAX_PROC_OPENS 1/*! @brief Name of the user block device. */#define USR_BLK_DEV_DEVICE_NAME_STR "usr_blk_dev"/*! @brief Support 8 partitions per card. */#define USR_BLK_DEV_SHIFT 3/* @brief The maximum number of sectors which can be included in a single request. */#define USR_BLK_DEV_MAX_SECTORS_PER_REQ 128/*! @brief Used to enable debugging messages to be sent out the system log. *//* #define USR_BLK_DEV_DEBUG *//*! @brief Macro used to send debug messages to the system log. */#ifdef USR_BLK_DEV_DEBUG# define tracemsg(fmt,args...) printk(__FILE__": %s: "fmt,__func__,##args)#else# define tracemsg(fmt,args...)#endif/*! * @brief Macro to extract the device number from the device node. * * Each device has 8 minor numbers since* USR_BLK_DEV_SHIFT is currently 3. * This results in the device number being stored in upper bits. */#define USR_BLK_DEV_DEVICE_NR(i_rdev) (MINOR(i_rdev)>>USR_BLK_DEV_SHIFT)/*! * @brief Timer used to debounce the insertion of a card. * * Only one timer is used for all of the devices. */static struct timer_list usr_blk_dev_timer;/*! * @brief The possible states of the media detection state machine. * * A list of the possible states of the card detection state machine which is * implemented in usr_blk_dev_poll_card_attach(). * * @note Removal is not debounced since a media card may have its power removed * at the point at which it is detected as removed only once. In this case the * safest thing to do is to reinitialize the card. */typedef enum{ /*! @brief The media is currently not connected. */ USR_BLK_DEV_DEBOUNCE_STATE_REMOVED, /*! * @brief The media card has been detected as inserted and is being debounced. * * The media card has been detected as inserted at least once. The number of * states determines the number of times the card must be detected as inserted * before it will be reported as such. */ /* @{ */ USR_BLK_DEV_DEBOUNCE_STATE_INSERTING, USR_BLK_DEV_DEBOUNCE_STATE_INSERTING1, USR_BLK_DEV_DEBOUNCE_STATE_INSERTING2, USR_BLK_DEV_DEBOUNCE_STATE_INSERTING3, USR_BLK_DEV_DEBOUNCE_STATE_INSERTING4, /* @} */ /*! * @brief The card has been debounced as inserted, the driver must be informed. * * Once the card is detected as inserted the rest of the driver must be informed. * However, this may take several iterations if the thread still has not received * the previous state change. This state will wait until the thread is ready to * receive the indication before sending it. */ USR_BLK_DEV_DEBOUNCE_STATE_UPDATE_INSERT, /* @brief The media is currently inserted. */ USR_BLK_DEV_DEBOUNCE_STATE_INSERTED, /* Removal is not debounced, so no REMOVING state exists. */ /*! * @brief The card has been debounced as removed, the driver must be informed. * * Once the card is detected as removed the rest of the driver must be informed. * However, this may take several iterations if the thread still has not received * the previous state change. This state will wait until the thread is ready to * receive the indication before sending it. */ USR_BLK_DEV_DEBOUNCE_STATE_UPDATE_REMOVAL} USR_BLK_DEV_DEBOUNCE_STATE_T;/*! * @brief The possible sources of commands for the kernel thread to send. * * There are three different sources of a command from the kernel: * - The detect interrupt, * - The request queue, * - A user process calling open, close, read, write etc. */typedef enum{ USR_BLK_DEV_CMD_SRC_IRQ, /*!< The command came from the detect interrupt. */ USR_BLK_DEV_CMD_SRC_REQ, /*!< The command came from the request queue. */ USR_BLK_DEV_CMD_SRC_GEN, /*!< The command came from a general source which can block. */ USR_BLK_DEV_CMD_SRC__END} USR_BLK_DEV_CMD_SRC_T;/*! * @brief The state of the command being processed. * * A typical command will have the following states. If the command originated * in an interrupt or from the request queue, it will not progress though the * final states, since there is no need to respond to the calling layer. Please * note there is a difference between a command which came from the kernel * request queue and once which is being handled by the RW code from within the * thread. The thread based read write commands progress through all of the * states. */typedef enum{ /*! No command is active. */ USR_BLK_DEV_CMD_STATE_NONE /*! A command request has been made by one of the three sources. */, USR_BLK_DEV_CMD_STATE_NEW, /*! The thread has received the command and has begun to act upon it. */ USR_BLK_DEV_CMD_STATE_THREAD, /*! The thread is waiting for the user space driver to read the command. */ USR_BLK_DEV_CMD_STATE_USR_READ, /*! * The command has been read by the user space process and the kernel thread * is waiting on the response. */ USR_BLK_DEV_CMD_STATE_USR_WAIT, /*! * The user space process has acted upon the command and written a response * to the /proc entry. */ USR_BLK_DEV_CMD_STATE_USR_DONE, /*! * The thread has completed operating on the command, and passed the data * back to the originator of the command. */ USR_BLK_DEV_CMD_STATE_THREAD_DONE} USR_BLK_DEV_CMD_STATE_T;/*! * @brief Structure which holds information on the devices attached. * * The following is used as an array indexed by the device number to store any * data needed by the driver. Please see the individual entries for details on * what is stored. */typedef struct{ /*! * @brief The current state of debouncing for the device. * * A simple state machine is used for debouncing the insertion and removal * of the card. This is the state counter for that machine. It can also * be used to determine the status of the card at any time while running. */ USR_BLK_DEV_DEBOUNCE_STATE_T debounce_state; /*! * @brief Used to track the connection state of the media.
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -