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