From patchwork Fri Feb 15 12:57:11 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Solomon Peachy X-Patchwork-Id: 2146621 Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 429A4DF24C for ; Fri, 15 Feb 2013 12:57:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1161339Ab3BOM5R (ORCPT ); Fri, 15 Feb 2013 07:57:17 -0500 Received: from cdptpa-omtalb.mail.rr.com ([75.180.132.120]:63900 "EHLO cdptpa-omtalb.mail.rr.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1161302Ab3BOM5P (ORCPT ); Fri, 15 Feb 2013 07:57:15 -0500 X-Authority-Analysis: v=2.0 cv=cYNQXw/M c=1 sm=0 a=QKCpt3RAcCy1PgeoOVilzg==:17 a=2oGSFm5vdZwA:10 a=wom5GMh1gUkA:10 a=SPIk0GJ5ZYsA:10 a=649elMfuWG0A:10 a=svWV0_fRAAAA:8 a=J6I8g3G7zlcA:10 a=7OxgBKDgRdCVjO4E4E8A:9 a=CjuIK1q_8ugA:10 a=xDfvBTzR90hTrO-PLg4A:9 a=32MgFfyDBOInY3sm:21 a=XeJu6-8LKkAol5Ti:21 a=oP-rUBIPtAaQ7pQkc0UA:9 a=QKCpt3RAcCy1PgeoOVilzg==:117 X-Cloudmark-Score: 0 X-Authenticated-User: X-Originating-IP: 24.73.230.86 Received: from [24.73.230.86] ([24.73.230.86:34470] helo=stuffed.shaftnet.org) by cdptpa-oedge03.mail.rr.com (envelope-from ) (ecelerity 2.2.3.46 r()) with ESMTP id AB/E3-11869-9A03E115; Fri, 15 Feb 2013 12:57:13 +0000 Received: from stuffed.shaftnet.org (localhost [127.0.0.1]) by stuffed.shaftnet.org (8.14.5/8.14.5) with ESMTP id r1FCvBlG016479 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 15 Feb 2013 07:57:11 -0500 Received: (from pizza@localhost) by stuffed.shaftnet.org (8.14.5/8.14.5/Submit) id r1FCvBiC016478; Fri, 15 Feb 2013 07:57:11 -0500 Date: Fri, 15 Feb 2013 07:57:11 -0500 From: Solomon Peachy To: Ivo Van Doorn Cc: linux-wireless , Gertjan van Wingerde , Helmut Schaa Subject: [PATCH/RFC v2] Add eeprom write supprot to rt2800usb Message-ID: <20130215125710.GB23323@shaftnet.org> References: <1360872580-24334-1-git-send-email-pizza@shaftnet.org> <1360872580-24334-2-git-send-email-pizza@shaftnet.org> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) X-Virus-Scanned: clamav-milter 0.97.6 at stuffed.shaftnet.org X-Virus-Status: Clean X-Spam-Status: No, score=1.6 required=4.0 tests=ALL_TRUSTED, DATE_IN_FUTURE_96_Q autolearn=no version=3.3.2 X-Spam-Level: * X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on stuffed.shaftnet.org Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org On Thu, Feb 14, 2013 at 09:25:56PM +0100, Ivo Van Doorn wrote: > rt2800 specific code doesn't belong in the generic code. You should > make your solution completely driver independent. Okay, I've attached my current WIP code. I want to make sure I'm on an acceptible track before I proceed further. This patch is more invasive than the first, but functionally it's identical to my first patch. Comments? - Solomon diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 197b446..82221e0 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -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); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index a128cea..3c5452d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -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); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 9224d87..7782002 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -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) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 85a4b62..9a90fa1 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -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 = { diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 0751b35..8fd81f5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -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); }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 3bb8caf..1b8de4b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -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); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 323ca7b..f8ed3de 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -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