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

📄 usr_blk_dev.c

📁 包含MMC协议,驱动源码. 在LINUX操作系统下通过.
💻 C
📖 第 1 页 / 共 5 页
字号:
        usr_blk_dev_send_cmd_to_thread(attached ? USR_BLK_DEV_CMD_ID_INIT : USR_BLK_DEV_CMD_ID_REMOVE,                                       dev_num, USR_BLK_DEV_CMD_SRC_IRQ);    }    return true;}/*! * @brief Returns true if the device is attached. * * @param dev_num The number of the device which needs to be checked * * @return true if the device is attached *         false if the device is removed */static bool usr_blk_dev_check_dev_attached(unsigned int dev_num){    tracemsg("\n");    /* At this time only one device is supported. */    return (USR_BLK_DEV_IS_DEV1_ATTACHED);}/*! * @brief Enables or disables the detection interrupt for a device. * * @param dev_num The device number which must be enabled. * @param enable  true if the interrupt must be enabled.<BR> *                false if the interrupt must be disabled. */static void usr_blk_dev_set_irq_state(unsigned int dev_num, bool enable){    tracemsg("%d\n", enable);    /* Currently only one device is supported. */#ifndef CONFIG_ARCH_SCMA11    if (enable)    {        enable_irq(IRQ_GPIO(USR_BLK_DEV_DEV1_INT_GPIO));    }    else    {        disable_irq(IRQ_GPIO(USR_BLK_DEV_DEV1_INT_GPIO));    }#endif}/*! * @brief Called each time the attach signal must be polled. * * Checks the attach state of a device and updates the debounce state based * on the status.  Only the attached state is debounced.  For removal, a single * interrupt or poll indicating removal, is all that is necessary to indicate the * media has been removed.  This is to insure the proper power up sequence is * sent to the device if power was removed. * * The debounce is implemented as a state machine in order to handle the different * debounce counts for removal and insertion as well as special requirements for * sending the media state indication to the command handling thread.  If the * thread has not processed a previous card attach state change, a new state * change cannot be sent.  For this reason the "UPDATE" states are present.  See * USR_BLK_DEV_DEBOUNCE_STATE_T for more details. * * @param dev_num The device number to operate on * * @return true if the device is in a steady state.<BR> *         false if the debouncing must continue. */static bool usr_blk_dev_poll_card_attach(unsigned int dev_num){    bool attached;    bool debounce_done;    USR_BLK_DEV_INFO_T *info_p;    info_p = &usr_blk_dev_info[dev_num];    attached = usr_blk_dev_check_dev_attached(dev_num);    debounce_done = false;    tracemsg("debounce state: %d media_state: %d attached: %d\n",             info_p->debounce_state, info_p->media_state, attached);    switch (info_p->debounce_state)    {        /*         * The device is currently removed.         */        case USR_BLK_DEV_DEBOUNCE_STATE_REMOVED:            /* Move on to the next state if the device is now inserted. */            if (attached)            {                info_p->debounce_state = USR_BLK_DEV_DEBOUNCE_STATE_INSERTING;            }            else            {                debounce_done = true;            }            break;        /*         * The device has been detected as inserted but has not been debounced.         */        case USR_BLK_DEV_DEBOUNCE_STATE_INSERTING:        case USR_BLK_DEV_DEBOUNCE_STATE_INSERTING1:        case USR_BLK_DEV_DEBOUNCE_STATE_INSERTING2:        case USR_BLK_DEV_DEBOUNCE_STATE_INSERTING3:        case USR_BLK_DEV_DEBOUNCE_STATE_INSERTING4:            if (attached)            {                info_p->debounce_state++;            }            else            {                info_p->debounce_state = USR_BLK_DEV_DEBOUNCE_STATE_REMOVED;            }            break;                    /*         * The device has been detected as inserted and the driver needs to be         * informed of the new state.         */        case USR_BLK_DEV_DEBOUNCE_STATE_UPDATE_INSERT:            if (attached)            {                if (usr_blk_dev_set_attached_state(dev_num, attached))                {                    info_p->debounce_state = USR_BLK_DEV_DEBOUNCE_STATE_INSERTED;                }            }            else            {                /*                 * If the device has been removed and it has not been reported as                 * inserted, go back to the removed state.                 */                info_p->debounce_state = USR_BLK_DEV_DEBOUNCE_STATE_REMOVED;            }            break;        /*         * The device is currently inserted.         */        case USR_BLK_DEV_DEBOUNCE_STATE_INSERTED:            if (!attached)            {                info_p->debounce_state = USR_BLK_DEV_DEBOUNCE_STATE_UPDATE_REMOVAL;            }            else            {                debounce_done = true;            }            break;        /*         * The device has been detected as removed and the driver needs to be         * informed of the new state.         */        case USR_BLK_DEV_DEBOUNCE_STATE_UPDATE_REMOVAL:            if (usr_blk_dev_set_attached_state(dev_num, false))            {                info_p->debounce_state = USR_BLK_DEV_DEBOUNCE_STATE_REMOVED;            }            break;        default:            info_p->debounce_state = USR_BLK_DEV_DEBOUNCE_STATE_UPDATE_REMOVAL;            break;    }    return debounce_done;}/*! * @brief Timer function called to handle debouncing of the card detect signal. * * Function loops through the possible devices and debounces them if the * corresponding bit is set in the device_msk.  If any devices require * further debouncing the timer is restarted.  If no more debouncing is * needed for a device it's interrupt is re-enabled.  If further debouncing * is needed the interrupt will be disabled. * * @param device_msk A bit mask which has the bits set for the devices *                   which must be debounced. */static void usr_blk_dev_timer_poll(unsigned long device_msk){    unsigned int dev_num;    static unsigned int timer_msk = 0;    unsigned int check_msk;    tracemsg("\n");    for (dev_num = 0; dev_num < USR_BLK_DEV_NUM_DEVICES; dev_num++)    {        check_msk = 1<<dev_num;        if (check_msk & ((unsigned int)device_msk))        {            /* Update the state, and if it no longer a steady state, start polling. */            if (!usr_blk_dev_poll_card_attach(dev_num))            {                /* Disable the card detect interrupt until the next steady state is reached. */                usr_blk_dev_set_irq_state(dev_num, false);                        /* Set up a timer to poll for a steady state on the card detect signal. */                timer_msk |= check_msk;            }            else            {                /* No reason to continue checking this device. */                timer_msk &= ~check_msk;                /* Re-enable the interrupt for the next card attach event. */                usr_blk_dev_set_irq_state(dev_num, true);            }        }    }    /* Restart the timer if not done debouncing. */    if (timer_msk)    {        tracemsg("Setting up timer for poll in 1 jiffy.\n");         usr_blk_dev_timer.function = usr_blk_dev_timer_poll;        usr_blk_dev_timer.data = (unsigned long)timer_msk;        usr_blk_dev_timer.expires = jiffies+1;        /* If the timer is running for more than the devices checked, simply update it. */        if ((timer_msk & ~((unsigned int)device_msk)) != 0)        {            mod_timer(&usr_blk_dev_timer, usr_blk_dev_timer.expires);        }        else        {            add_timer(&usr_blk_dev_timer);        }    }}/*! * @brief Interrupt handler for when a card detect signal changes state. * * This function is called once a change in state is detected.  As a result of * this function being called the interrupt will be disabled and the debounce * timer will be started.  See usr_blk_dev_timer_poll() for all of the details * on debouncing. * * @param irq        Not used in this function, but required by the caller. * @param device_msk The device mask to operate on. * @param regs       Not used in this function, but required by the caller. */static void usr_blk_dev_attach_irq(int irq, void *device_msk, struct pt_regs *regs){    tracemsg("\n");    /* Take a sample and set up a timer if not in a steady state already. */    usr_blk_dev_timer_poll((unsigned long)device_msk);}/*! * @brief Clears out the data necessary once a command is processed. * * This function must be called once a command has been processed by the block * device thread and the data has been processed by the function which requested * the command.  For example if the request came from * usr_blk_dev_check_media_change(), usr_blk_dev_check_media_change() must call * this function to allow other commands to be processed.  Any commands requested * during the processing of this command will be waiting until this command is * processed. * * @param info_p  Pointer to the information structure for the device being *                operated upon. * @param cmd_src The source of the command. * * @todo  Only the GEN user actually needs to be woken up.  It may make more *        sense to move the wait queue out of the command structure. */static void usr_blk_dev_cmd_data_processed(    USR_BLK_DEV_INFO_T *info_p,    USR_BLK_DEV_CMD_SRC_T cmd_src){    struct usr_blk_dev_cmd_s *cmd_p;        tracemsg("\n");    cmd_p = &info_p->cmd[cmd_src];    cmd_p->data.id = USR_BLK_DEV_CMD_ID_NONE;    cmd_p->state = USR_BLK_DEV_CMD_STATE_NONE;    wake_up(&cmd_p->wait_for_completion);}/*! * @brief Sends a command to the thread and waits for the kernel thread to *        complete processing of the command. * * Sets up a command to be sent to kernel thread and waits for the kernel thread * to respond to the command.  This function will block until the response is * received from the user space driver and processed by the kernel thread.  It * should not be used from the request queue or an interrupt. * * @param info_p  Pointer to the information structure for the device being *                operated upon. * @param id      The command to send. * @param dev_num The device which the command must be sent to. * @param cmd_src The source of the command. * * @note: Do not call this from a context which cannot block.  For that *        case usr_blk_dev_send_cmd_to_thread() must be used. */static void usr_blk_dev_send_cmd_to_thread_and_wait(    USR_BLK_DEV_INFO_T *info_p,    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;        tracemsg("id: %d cmd_src:%d\n", id, cmd_src);    cmd_p = &info_p->cmd[cmd_src];    usr_blk_dev_send_cmd_to_thread(id, dev_num, cmd_src);    /* Wait for thread to respond to the command. */    wait_event(cmd_p->wait_for_thread,               ((cmd_p->state == USR_BLK_DEV_CMD_STATE_THREAD_DONE) ||                (info_p->media_state == USR_BLK_DEV_MEDIA_STATE_ERROR)));    tracemsg("Thread command response received.\n");}/*! * @brief Clears out the data necessary once a command is processed. * * This must be called once the user block thread is done processing a command. * It will clear out the necessary data and set the state to * USR_BLK_DEV_CMD_STATE_THREAD_DONE.  If the command was not from an interrupt * or the request queue, the sending routine will be woken up. * * @param info_p  Pointer to the information structure for the device which *                the command has been completed. * * @todo  Only the GEN user actually needs to be woken up.  It may make more *        sense to move the wait queue out of the command structure. */static void usr_blk_dev_thread_cmd_done(USR_BLK_DEV_INFO_T *info_p){    struct usr_blk_dev_cmd_s *cmd_p;        tracemsg("id: %d cmd_src: %d\n", info_p->cmd[info_p->cmd_src].data.id, info_p->cmd_src);    cmd_p = &info_p->cmd[info_p->cmd_src];    cmd_p->state = USR_BLK_DEV_CMD_STATE_THREAD_DONE;    /*     * If the source of the command was the request queue or an interrupt, no completed     * ack or return data is supported.     */    if ((info_p->cmd_src == USR_BLK_DEV_CMD_SRC_IRQ) || (info_p->cmd_src == USR_BLK_DEV_CMD_SRC_REQ))    {        cmd_p->data.id = USR_BLK_DEV_CMD_ID_NONE;        cmd_p->state = USR_BLK_DEV_CMD_STATE_NONE;

⌨️ 快捷键说明

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