?? usr_blk_dev.c
字號:
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 + -