⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usr_blk_dev.c

📁 包含MMC协议,驱动源码. 在LINUX操作系统下通过.
💻 C
📖 第 1 页 / 共 5 页
字号:
     */    USR_BLK_DEV_MEDIA_STATE_T media_state;    /*!     * @brief true of the device has been validated at least once since it was     *        attached.     */    uint8_t validated;    /*!     * @brief true if the media has changed since the last time ioctl was called     *        with IOCMMCGETCARDSTATUS.     */    uint8_t ioctl_media_changed;    /*!     * @brief Keep track of the number of times the proc entry for the device has     *        been opened.     */    uint8_t proc_opens;    /*!     * @brief Wait queue used when the user mode process is waiting for data from     *        the kernel block driver.     */    wait_queue_head_t wait_for_usr_read;    /*!     * @brief Wait queue used when the kernel block driver is waiting for a     *        response from the user mode process.     */    wait_queue_head_t wait_for_usr_write;    /*!     * @brief The init data which is kept while the driver is running for     *        convenience.     */    USR_BLK_DEV_INIT_DATA_T params;    /*!     * @brief The source of the command being sent to user space.     *     * Indicates which source the command currently being sent to user space is     * from.  This allows the proc functions to copy data to and from the correct     * buffers.     */    USR_BLK_DEV_CMD_SRC_T cmd_src;    /*!     * @brief Array which holds commands from the different sources.     *     * Array which holds commands from the different sources. This is necessary     * so that the different sources which cannot block can place their commands     * somewhere.  This is done in lieu of a queue to save memory.  It is     * possible for the interrupt code to overwrite a command before it is     * processed, but this is acceptable as the card can only be inserted and     * removed by the interrupt.     */    struct usr_blk_dev_cmd_s    {        /*!         * @brief Wait queue used to wait before a new command can be added to         *        the data register.         *          * @note This is not used for the interrupt and request queue since they cannot block.         */        wait_queue_head_t wait_for_completion;        /*!         * @brief Wait queue used to wait for the kernel thread to complete         * processing of the command.  Once the kernel thread is done operating         * on the command the data can be processed.          */        wait_queue_head_t wait_for_thread;        /*!         * @brief The current state of the command.         *         * The current state of the command is used by the wait queue code to         * determine when it is acceptable to awaken.         */        USR_BLK_DEV_CMD_STATE_T state;        /*!         * @brief The command currently being sent to or processed by the user         *        mode driver.         */        USR_BLK_DEV_CMD_T data;    } cmd[USR_BLK_DEV_CMD_SRC__END];    /*!     * @brief The request queue used by this device.     *     * The request queue used by this device.  In the case of multiple cards     * each will have its own request queue to maximize performance.     */    request_queue_t req_queue;} USR_BLK_DEV_INFO_T;/******************************************************************************* Local variables******************************************************************************//*! * @brief Array of device information indexed by the the device number, not *        the minor number. */USR_BLK_DEV_INFO_T usr_blk_dev_info[USR_BLK_DEV_NUM_DEVICES];/*! * @brief Define the maximum number of sectors which can be sent in a single * read or write command.  This array is indexed by minor number. */static int usr_blk_dev_max_sectors[USR_BLK_DEV_NUM_DEVICES<<USR_BLK_DEV_SHIFT];/*! * @brief Used to define the block sizes of the device.  This array is indexed *        by minor number. */static int usr_blk_dev_blksizes[USR_BLK_DEV_NUM_DEVICES<<USR_BLK_DEV_SHIFT];/*! * @brief The partition information needed for gendisk.  One entry per *        partition.  (Each minor number is a partition.) */static struct hd_struct usr_blk_dev_partitions[USR_BLK_DEV_NUM_DEVICES<<USR_BLK_DEV_SHIFT];/*! * @brief The partition sizes needed by gendisk in number of sectors. * * The partition size sizes user by gendisk.  These are kept in number of * sectors and are filled in by the call to register_disk(). */static int usr_blk_dev_sizes[USR_BLK_DEV_NUM_DEVICES<<USR_BLK_DEV_SHIFT];/* Forward declaration of the operations to allow compilation. */extern const struct block_device_operations usr_blk_dev_ops;/*! * @brief The generic disk structure which will hold the partition data for *        the devices. */static struct gendisk usr_blk_dev_gendisk ={    .major        = USR_BLK_DEV_MAJOR_NUM,    .major_name   = USR_BLK_DEV_DEVICE_NAME_STR,    .minor_shift  = USR_BLK_DEV_SHIFT,    .fops         = (struct block_device_operations *)&usr_blk_dev_ops,    .max_p        = 1<<USR_BLK_DEV_SHIFT,    .part         = usr_blk_dev_partitions,    .sizes        = usr_blk_dev_sizes,    .nr_real      = 0,    .real_devices = NULL};/*! * @brief Wait queue used to wake up the thread used to send commands from *        interrupts. */#ifndef DOXYGEN_SHOULD_SKIP_THISstatic DECLARE_WAIT_QUEUE_HEAD(usr_blk_dev_thread_wait);#endif/******************************************************************************* Local functions******************************************************************************/#if ((!defined CONFIG_OMAP_INNOVATOR) && (defined CONFIG_HOTPLUG))# ifndef DOXYGEN_SHOULD_SKIP_THIS/* * External variables and functions needed by the hotplug code which are not * in any header files. */extern char hotplug_path[];extern int call_usermodehelper(char *path, char **argv, char **envp);# endif/*! * @brief Calls hotplug with parameters based on if the device is attached. * * Executes the hotplug executable passing it the needed information.  The * device status is determined from the parameter attached and the device * assumed to be mmc.  This allows it to operate using the same files as * the standard mmc driver. * * @param dev_num  The device number for which hotplug will be called.  This *                 cannot be larger than 9. * @param attached true if the device is attached and false it it is *                 detached. */static void usr_blk_dev_hotplug(unsigned int dev_num,  bool attached){    char slot_str[] = "SLOT= ";    const char action_add_str[] = "ACTION=add";    const char action_remove_str[] = "ACTION=remove";    const char *argv[] =    {        hotplug_path,        "mmc",        NULL    };    const char *envp[] =    {        "HOME=/",        "PATH=/sbin:/bin:/usr/sbin:/usr/bin",        slot_str,        "MEDIA=mmc",        action_add_str,        NULL    };    int ret;    if ((hotplug_path[0]) && (dev_num <= 9))    {        /* Place the device number in the slot string. */        slot_str[5] = '0'+dev_num;        /* Update the action string if the device is not attached. */        if (!attached)        {            envp[4] = action_remove_str;        }        ret = call_usermodehelper((char *)argv[0], (char **)argv, (char **)envp);        tracemsg("%s (%s %s) returned: %d\n", argv[0], envp[2], envp[4], ret);    }}#else# define usr_blk_dev_hotplug(dev, attached)#endif/*! * @brief Sends a command to the kernel thread. * * Sends a command to the block driver thread to be sent to the user process. * This function may block if a command is currently in process and the source * of the command is not the request queue or the detect interrupt.  (In other * words, the function will not block for the request queue and interrupt sources.) * The detect interrupt and request queue code must protect against overwriting a * previous command which has not yet been processed. * * @param id      The command to send to the kernel thread. * @param dev_num The device number which the command is for. * @param cmd_src The source of the command  */static void usr_blk_dev_send_cmd_to_thread(    USR_BLK_DEV_CMD_ID_T id,    unsigned int dev_num,    USR_BLK_DEV_CMD_SRC_T cmd_src){    struct usr_blk_dev_cmd_s *cmd_p;    USR_BLK_DEV_INFO_T *info_p;    info_p = &usr_blk_dev_info[dev_num];    cmd_p = &info_p->cmd[cmd_src];    tracemsg("id: %d cmd_src: %d cmd state: %d media_state: %d\n", id, cmd_src, cmd_p->state, info_p->media_state);    /*     * If this is a command from the request queue and a request command is already pending     * simply ignore it, since it will be picked up from the request queue when the current     * request command completes.     */    if ((cmd_src == USR_BLK_DEV_CMD_SRC_REQ) && (cmd_p->state > USR_BLK_DEV_CMD_STATE_NONE))    {        return;    }    /*     * If the source is not an interrupt block if a command is pending.     */    if ((cmd_src != USR_BLK_DEV_CMD_SRC_IRQ) && (cmd_src != USR_BLK_DEV_CMD_SRC_REQ))    {        wait_event(cmd_p->wait_for_completion,                   ((cmd_p->state == USR_BLK_DEV_CMD_STATE_NONE) ||                    (info_p->media_state == USR_BLK_DEV_MEDIA_STATE_ERROR)));    }    /*     * Set up to send the command.     */    cmd_p->data.id = id;    cmd_p->data.device_num = dev_num;    cmd_p->data.media_state = info_p->media_state;    cmd_p->state = USR_BLK_DEV_CMD_STATE_NEW;    wake_up(&usr_blk_dev_thread_wait);    tracemsg("Done\n");}/*! * @brief Aborts a command and sets the media state to ERROR. * * Aborts a command by setting the media state to error, the command state to * none and waking up any wait queues which might be waiting on data from the * command.  It is the responsibility of any code waiting on a queue to check * the media state for an indication of the error. * * @param info_p  Pointer to the information structure for the device being *                operated upon. */void usr_blk_dev_abort_cmd(USR_BLK_DEV_INFO_T *info_p){    struct usr_blk_dev_cmd_s *cmd_p;    cmd_p = &info_p->cmd[info_p->cmd_src];    tracemsg("id: %d cmd_src: %d cmd state: %d media_state: %d\n",             cmd_p->data.id, info_p->cmd_src, cmd_p->state, info_p->media_state);    cmd_p->state = USR_BLK_DEV_CMD_STATE_NONE;    info_p->media_state = USR_BLK_DEV_MEDIA_STATE_ERROR;    wake_up(&cmd_p->wait_for_completion);    wake_up(&cmd_p->wait_for_thread);    wake_up(&info_p->wait_for_usr_read);    wake_up(&info_p->wait_for_usr_write);}/*! * @brief Set up and send the init or remove command using the block driver thread. * * Sets up and sends the init or remove command to the block driver thread.  This * function does not protect against over writing a previous command sent to the * thread since there is no harm in updating the attached status at any time. * * @param dev_num  The number of the device which was just attached. * @param attached true if the device is attached, false is detached. * * @return true if the attached state was updated by the driver.<BR> *         false if the driver is busy and cannot update the attached state *         at this time */static bool usr_blk_dev_set_attached_state(unsigned int dev_num, bool attached){    USR_BLK_DEV_INFO_T *info_p;    USR_BLK_DEV_CMD_SRC_T i;    bool dev_attached;        info_p = &usr_blk_dev_info[dev_num];    tracemsg("attached: %d cmd state: %d proc_opens: %d\n",             attached, info_p->cmd[USR_BLK_DEV_CMD_SRC_IRQ].state, info_p->proc_opens);    dev_attached = info_p->media_state != USR_BLK_DEV_MEDIA_STATE_REMOVED;    info_p->media_state =        (attached != false) ? USR_BLK_DEV_MEDIA_STATE_ATTACHED : USR_BLK_DEV_MEDIA_STATE_REMOVED;    /*     * Update all command sources with the new command status.  This will allow the     * commands to abort if the card has been removed.     */    for (i = 0; i < USR_BLK_DEV_CMD_SRC__END; i++)    {        info_p->cmd[i].data.media_state = info_p->media_state;    }    /*     * If a previous attach state command is still being processed indicate     * this state change must wait.  If it does not wait the previous state     * change may be missed by the user driver.     */    if (info_p->cmd[USR_BLK_DEV_CMD_SRC_IRQ].state != USR_BLK_DEV_CMD_STATE_NONE)    {        return false;    }    /*     * Only send the command to the thread if the proc entry has been opened.  If it has     * not been opened, there is no user process to receive the command.  In this case it     * will be sent the first time the proc entry is opened.     */    if (info_p->proc_opens > 0)    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -