Commit fbe910e4 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] request_firmware(): add status bitmap

From: Manuel Estrada Sainz <ranty@ranty.pantax.net>

Based on patch and suggestions from Dmitry Torokhov

- Make an status bitmap instead of using independent boolean variables.  It
  will make things nicer later when new issues need to be tracked.
parent b0969714
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <asm/hardirq.h> #include <asm/hardirq.h>
#include <linux/bitops.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include "base.h" #include "base.h"
...@@ -21,6 +22,11 @@ MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>"); ...@@ -21,6 +22,11 @@ MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
MODULE_DESCRIPTION("Multi purpose firmware loading support"); MODULE_DESCRIPTION("Multi purpose firmware loading support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
enum {
FW_STATUS_LOADING,
FW_STATUS_ABORT,
};
static int loading_timeout = 10; /* In seconds */ static int loading_timeout = 10; /* In seconds */
struct firmware_priv { struct firmware_priv {
...@@ -28,8 +34,7 @@ struct firmware_priv { ...@@ -28,8 +34,7 @@ struct firmware_priv {
struct completion completion; struct completion completion;
struct bin_attribute attr_data; struct bin_attribute attr_data;
struct firmware *fw; struct firmware *fw;
int loading; unsigned long status;
int abort;
int alloc_size; int alloc_size;
struct timer_list timeout; struct timer_list timeout;
}; };
...@@ -37,7 +42,7 @@ struct firmware_priv { ...@@ -37,7 +42,7 @@ struct firmware_priv {
static inline void static inline void
fw_load_abort(struct firmware_priv *fw_priv) fw_load_abort(struct firmware_priv *fw_priv)
{ {
fw_priv->abort = 1; set_bit(FW_STATUS_ABORT, &fw_priv->status);
wmb(); wmb();
complete(&fw_priv->completion); complete(&fw_priv->completion);
} }
...@@ -99,7 +104,8 @@ static ssize_t ...@@ -99,7 +104,8 @@ static ssize_t
firmware_loading_show(struct class_device *class_dev, char *buf) firmware_loading_show(struct class_device *class_dev, char *buf)
{ {
struct firmware_priv *fw_priv = class_get_devdata(class_dev); struct firmware_priv *fw_priv = class_get_devdata(class_dev);
return sprintf(buf, "%d\n", fw_priv->loading); int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
return sprintf(buf, "%d\n", loading);
} }
/** /**
...@@ -116,26 +122,26 @@ firmware_loading_store(struct class_device *class_dev, ...@@ -116,26 +122,26 @@ firmware_loading_store(struct class_device *class_dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct firmware_priv *fw_priv = class_get_devdata(class_dev); struct firmware_priv *fw_priv = class_get_devdata(class_dev);
int prev_loading = fw_priv->loading; int loading = simple_strtol(buf, NULL, 10);
fw_priv->loading = simple_strtol(buf, NULL, 10);
switch (fw_priv->loading) { switch (loading) {
case 1: case 1:
vfree(fw_priv->fw->data); vfree(fw_priv->fw->data);
fw_priv->fw->data = NULL; fw_priv->fw->data = NULL;
fw_priv->fw->size = 0; fw_priv->fw->size = 0;
fw_priv->alloc_size = 0; fw_priv->alloc_size = 0;
set_bit(FW_STATUS_LOADING, &fw_priv->status);
break; break;
case 0: case 0:
if (prev_loading == 1) { if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
complete(&fw_priv->completion); complete(&fw_priv->completion);
clear_bit(FW_STATUS_LOADING, &fw_priv->status);
break; break;
} }
/* fallthrough */ /* fallthrough */
default: default:
printk(KERN_ERR "%s: unexpected value (%d)\n", __FUNCTION__, printk(KERN_ERR "%s: unexpected value (%d)\n", __FUNCTION__,
fw_priv->loading); loading);
/* fallthrough */ /* fallthrough */
case -1: case -1:
fw_load_abort(fw_priv); fw_load_abort(fw_priv);
...@@ -370,7 +376,7 @@ request_firmware(const struct firmware **firmware, const char *name, ...@@ -370,7 +376,7 @@ request_firmware(const struct firmware **firmware, const char *name,
del_timer_sync(&fw_priv->timeout); del_timer_sync(&fw_priv->timeout);
fw_remove_class_device(class_dev); fw_remove_class_device(class_dev);
if (fw_priv->fw->size && !fw_priv->abort) { if (fw_priv->fw->size && !test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
*firmware = fw_priv->fw; *firmware = fw_priv->fw;
} else { } else {
retval = -ENOENT; retval = -ENOENT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment