The firmware user helper code tracks the current state of the loading
process via unsigned long status and a complection in struct
firmware_buf. We only need this for the usermode helper as such we can
encapsulate all this data into its own data structure.
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+
+enum {
+ FW_UMH_UNKNOWN,
+ FW_UMH_LOADING,
+ FW_UMH_DONE,
+ FW_UMH_ABORTED,
+};
+struct fw_umh {
+ struct completion completion;
+ unsigned long status;
+};
+
+static void fw_umh_init(struct fw_umh *fw_umh)
+{
+ init_completion(&fw_umh->completion);
+ fw_umh->status = FW_UMH_UNKNOWN;
+}
+
+static int __fw_umh_check(struct fw_umh *fw_umh, unsigned long status)
+{
+ return test_bit(status, &fw_umh->status);
+}
+
+static int fw_umh_wait_timeout(struct fw_umh *fw_umh, long timeout)
+{
+ int ret;
+
+ ret = wait_for_completion_interruptible_timeout(&fw_umh->completion,
+ timeout);
+ if (ret != 0 && test_bit(FW_UMH_ABORTED, &fw_umh->status))
+ return -ENOENT;
+
+ return ret;
+}
+
+static void __fw_umh_set(struct fw_umh *fw_umh,
+ unsigned long status)
+{
+ set_bit(status, &fw_umh->status);
+
+ if (status == FW_UMH_DONE || status == FW_UMH_ABORTED) {
+ clear_bit(FW_UMH_LOADING, &fw_umh->status);
+ complete_all(&fw_umh->completion);
+ }
+}
+
+#define fw_umh_start(fw_umh) \
+ __fw_umh_set(fw_umh, FW_UMH_LOADING)
+#define fw_umh_done(fw_umh) \
+ __fw_umh_set(fw_umh, FW_UMH_DONE)
+#define fw_umh_aborted(fw_umh) \
+ __fw_umh_set(fw_umh, FW_UMH_ABORTED)
+#define fw_umh_is_loading(fw_umh) \
+ __fw_umh_check(fw_umh, FW_UMH_LOADING)
+#define fw_umh_is_done(fw_umh) \
+ __fw_umh_check(fw_umh, FW_UMH_DONE)
+#define fw_umh_is_aborted(fw_umh) \
+ __fw_umh_check(fw_umh, FW_UMH_ABORTED)
+
+#else /* CONFIG_FW_LOADER_USER_HELPER */
+
+#define fw_umh_wait_timeout(fw_st, long) 0
+
+#define fw_umh_done(fw_st)
+#define fw_umh_is_done(fw_st) true
+#define fw_umh_is_aborted(fw_st) false
@@ -309,8 +373,7 @@ static void fw_finish_direct_load(struct device *device,
struct firmware_buf *buf)
{
mutex_lock(&fw_lock);
- set_bit(FW_STATUS_DONE, &buf->status);
- complete_all(&buf->completion);
+ fw_umh_done(&buf->fw_umh);
mutex_unlock(&fw_lock);
}
/* wait until the shared firmware_buf becomes ready (or error) */
static int sync_cached_firmware_buf(struct firmware_buf *buf)
{
int ret = 0;
mutex_lock(&fw_lock);
- while (!test_bit(FW_STATUS_DONE, &buf->status)) {
- if (is_fw_load_aborted(buf)) {
+ while (!fw_umh_is_done(&buf->fw_umh)) {
+ if (fw_umh_is_aborted(&buf->fw_umh)) {
ret = -ENOENT;
break;
}
mutex_unlock(&fw_lock);
- ret = wait_for_completion_interruptible(&buf->completion);
+ ret = fw_umh_wait_timeout(&buf->fw_umh, 0);
mutex_lock(&fw_lock);
}