@@ -4574,7 +4574,8 @@ int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_efuse_detect);
-static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
+static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev,
+ u16 *eeprom, unsigned int i)
{
u32 reg;
u16 efuse_ctrl_reg;
@@ -4609,23 +4610,24 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
/* Apparently the data is read from end to start */
rt2800_register_read_lock(rt2x00dev, efuse_data3_reg, ®);
/* The returned value is in CPU order, but eeprom is le */
- *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg);
+ *(u32 *)&eeprom[i] = cpu_to_le32(reg);
rt2800_register_read_lock(rt2x00dev, efuse_data2_reg, ®);
- *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
+ *(u32 *)&eeprom[i + 2] = cpu_to_le32(reg);
rt2800_register_read_lock(rt2x00dev, efuse_data1_reg, ®);
- *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg);
+ *(u32 *)&eeprom[i + 4] = cpu_to_le32(reg);
rt2800_register_read_lock(rt2x00dev, efuse_data0_reg, ®);
- *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg);
+ *(u32 *)&eeprom[i + 6] = cpu_to_le32(reg);
mutex_unlock(&rt2x00dev->csr_mutex);
}
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev,
+ u16 *eeprom, const u16 length)
{
unsigned int i;
- for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
- rt2800_efuse_read(rt2x00dev, i);
+ for (i = 0; i < length / sizeof(u16); i += 8)
+ rt2800_efuse_read(rt2x00dev, eeprom, i);
}
EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
@@ -207,7 +207,8 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
-void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
+void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev,
+ u16 *eeprom, const u16 length);
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
@@ -173,7 +173,7 @@ static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
- rt2800_read_eeprom_efuse(rt2x00dev);
+ rt2800_read_eeprom_efuse(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
}
#else
static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
@@ -733,12 +733,43 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
}
/*
+ * EEPROM manipulation functions,
+ */
+static int rt2800usb_load_eeprom(struct rt2x00_dev *rt2x00dev,
+ u16 *eeprom, const u16 length)
+{
+ u16 len = min_t(u16, length, EEPROM_SIZE);
+
+ if (rt2800_efuse_detect(rt2x00dev))
+ rt2800_read_eeprom_efuse(rt2x00dev, eeprom,
+ len);
+ else
+ rt2x00usb_eeprom_read(rt2x00dev, eeprom, len);
+
+ return len;
+}
+
+static int rt2800usb_store_eeprom(struct rt2x00_dev *rt2x00dev,
+ u16 *eeprom, const u16 length)
+{
+ u16 len = min_t(u16, length, EEPROM_SIZE);
+
+ if (rt2800_efuse_detect(rt2x00dev))
+ return -EINVAL;
+
+ rt2x00usb_eeprom_write(rt2x00dev, eeprom, len);
+
+ return length;
+}
+
+/*
* Device probe functions.
*/
static void rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
if (rt2800_efuse_detect(rt2x00dev))
- rt2800_read_eeprom_efuse(rt2x00dev);
+ rt2800_read_eeprom_efuse(rt2x00dev, rt2x00dev->eeprom,
+ EEPROM_SIZE);
else
rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
EEPROM_SIZE);
@@ -844,6 +875,9 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.config = rt2800_config,
.sta_add = rt2800_sta_add,
.sta_remove = rt2800_sta_remove,
+
+ .eeprom_load = rt2800usb_load_eeprom,
+ .eeprom_store = rt2800usb_store_eeprom,
};
static const struct data_queue_desc rt2800usb_queue_rx = {
@@ -648,6 +648,12 @@ struct rt2x00lib_ops {
struct ieee80211_sta *sta);
int (*sta_remove) (struct rt2x00_dev *rt2x00dev,
int wcid);
+
+ /* EEPROM manipulation */
+ int (*eeprom_load) (struct rt2x00_dev *rt2x00dev,
+ u16 *eeprom, const u16 max_length);
+ int (*eeprom_store) (struct rt2x00_dev *rt2x00dev,
+ u16 *eeprom, const u16 max_length);
};
/*
@@ -86,6 +86,7 @@ struct rt2x00debug_intf {
struct dentry *csr_val_entry;
struct dentry *eeprom_off_entry;
struct dentry *eeprom_val_entry;
+ struct dentry *eeprom_commit_entry;
struct dentry *bbp_off_entry;
struct dentry *bbp_val_entry;
struct dentry *rf_off_entry;
@@ -650,6 +651,44 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
}
+static ssize_t rt2x00debug_eeprom_commit_write(struct file *file,
+ const char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+
+ if (intf->rt2x00dev->ops->lib->eeprom_store)
+ intf->rt2x00dev->ops->lib->eeprom_store(intf->rt2x00dev,
+ intf->rt2x00dev->eeprom,
+ intf->rt2x00dev->ops->eeprom_size);
+
+ return length;
+}
+static ssize_t rt2x00debug_eeprom_commit_read(struct file *file,
+ char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+
+ if (intf->rt2x00dev->ops->lib->eeprom_load)
+ intf->rt2x00dev->ops->lib->eeprom_load(intf->rt2x00dev,
+ intf->rt2x00dev->eeprom,
+ intf->rt2x00dev->ops->eeprom_size);
+
+ return 0;
+}
+
+static const struct file_operations rt2x00debug_fop_eeprom_commit = {
+ .owner = THIS_MODULE,
+ .write = rt2x00debug_eeprom_commit_write,
+ .read = rt2x00debug_eeprom_commit_read,
+ .open = rt2x00debug_file_open,
+ .release = rt2x00debug_file_release,
+ .llseek = default_llseek,
+};
+
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
@@ -730,6 +769,13 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
+ intf->eeprom_commit_entry =
+ debugfs_create_file("eeprom_commit", S_IRUSR | S_IWUSR,
+ intf->register_folder,
+ intf, &rt2x00debug_fop_eeprom_commit);
+ if (IS_ERR(intf->eeprom_commit_entry) || !intf->eeprom_commit_entry)
+ goto exit;
+
intf->queue_folder =
debugfs_create_dir("queue", intf->driver_folder);
if (IS_ERR(intf->queue_folder) || !intf->queue_folder)
@@ -786,6 +832,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
debugfs_remove(intf->bbp_off_entry);
debugfs_remove(intf->eeprom_val_entry);
debugfs_remove(intf->eeprom_off_entry);
+ debugfs_remove(intf->eeprom_commit_entry);
debugfs_remove(intf->csr_val_entry);
debugfs_remove(intf->csr_off_entry);
debugfs_remove(intf->register_folder);
@@ -203,6 +203,25 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
}
/**
+ * rt2x00usb_eeprom_write - Write eeprom to device
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @eeprom: Pointer to eeprom array to copy the information from
+ * @length: Number of bytes to write to the eeprom
+ *
+ * Simple wrapper around rt2x00usb_vendor_request to write the eeprom
+ * to the device. Note that the eeprom argument _must_ be allocated using
+ * kmalloc for correct handling inside the kernel USB layer.
+ */
+static inline int rt2x00usb_eeprom_write(struct rt2x00_dev *rt2x00dev,
+ __le16 *eeprom, const u16 length)
+{
+ return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_WRITE,
+ USB_VENDOR_REQUEST_OUT, 0, 0,
+ eeprom, length,
+ REGISTER_TIMEOUT16(length));
+}
+
+/**
* rt2x00usb_register_read - Read 32bit register word
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
* @offset: Register offset