135 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* arch/arm/mach-msm/htc_wifi_nvs.c
 | |
|  *
 | |
|  * Code to extract WiFi calibration information from ATAG set up 
 | |
|  * by the bootloader.
 | |
|  *
 | |
|  * Copyright (C) 2008 Google, Inc.
 | |
|  * Author: Dmitry Shmidt <dimitrysh@google.com>
 | |
|  *
 | |
|  * This software is licensed under the terms of the GNU General Public
 | |
|  * License version 2, as published by the Free Software Foundation, and
 | |
|  * may be copied, distributed, and modified under those terms.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/init.h>
 | |
| #include <linux/platform_device.h>
 | |
| #include <linux/proc_fs.h>
 | |
| 
 | |
| #include <asm/setup.h>
 | |
| #define ATAG_MSM_WIFI_DEBUG 1
 | |
| /* configuration tags specific to msm */
 | |
| #define ATAG_MSM_WIFI	0x57494649 /* MSM WiFi */
 | |
| 
 | |
| #define NVS_MAX_SIZE	0x800U
 | |
| #define NVS_LEN_OFFSET	0x0C
 | |
| #define NVS_DATA_OFFSET	0x40
 | |
| 
 | |
| static unsigned char wifi_nvs_ram[NVS_MAX_SIZE];
 | |
| static struct proc_dir_entry *wifi_calibration;
 | |
| static struct proc_dir_entry *wifi_data;
 | |
| 
 | |
| unsigned char *get_wifi_nvs_ram( void )
 | |
| {
 | |
| 	pr_info("NVS: get_wifi_nvs_ram\n");
 | |
| 	return wifi_nvs_ram;
 | |
| }
 | |
| EXPORT_SYMBOL(get_wifi_nvs_ram);
 | |
| 
 | |
| static int __init parse_tag_msm_wifi(const struct tag *tag)
 | |
| {
 | |
| 	pr_info("NVS: parse_tag_msm_wifi\n");
 | |
| 	unsigned char *dptr = (unsigned char *)(&tag->u);
 | |
| 	unsigned size;
 | |
| #ifdef ATAG_MSM_WIFI_DEBUG
 | |
| 	unsigned i;
 | |
| #endif
 | |
| 
 | |
| 	size = min((tag->hdr.size - 2) * sizeof(__u32), NVS_MAX_SIZE);
 | |
| #ifdef ATAG_MSM_WIFI_DEBUG
 | |
| 	printk("WiFi Data size = %d , 0x%x\n", tag->hdr.size, tag->hdr.tag);
 | |
| 	for(i=0;( i < size );i++) {
 | |
| 		printk("%02x ", *dptr++);
 | |
| 	}
 | |
| #endif	
 | |
| 	memcpy(wifi_nvs_ram, dptr, size);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| __tagtable(ATAG_MSM_WIFI, parse_tag_msm_wifi);
 | |
| 
 | |
| static unsigned wifi_get_nvs_size( void )
 | |
| {
 | |
| 	pr_info("NVS: wifi_get_nvs_size\n");
 | |
| 	unsigned char *ptr;
 | |
| 	unsigned len;
 | |
| 
 | |
| 	ptr = get_wifi_nvs_ram();
 | |
| 	/* Size in format LE assumed */
 | |
| 	memcpy(&len, ptr + NVS_LEN_OFFSET, sizeof(len));
 | |
| 	len = min(len, (NVS_MAX_SIZE - NVS_DATA_OFFSET));
 | |
| 	pr_info("NVS: wifi_get_nvs_size %d\n", len);
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| int wifi_calibration_size_set(void)
 | |
| {
 | |
| 	if (wifi_calibration != NULL)
 | |
| 		wifi_calibration->size = wifi_get_nvs_size();
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_WIFI_NVS_PROC_CREATE
 | |
| static int wifi_calibration_read_proc(char *page, char **start, off_t off,
 | |
| 					int count, int *eof, void *data)
 | |
| {
 | |
| 	pr_info("NVS: wifi_calibration_read_proc\n");
 | |
| 	unsigned char *ptr;
 | |
| 	unsigned len;
 | |
| 
 | |
| 	ptr = get_wifi_nvs_ram();
 | |
| 	len = min(wifi_get_nvs_size(), (unsigned)count);
 | |
| 	memcpy(page, ptr + NVS_DATA_OFFSET, len);
 | |
| 	return len;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static int wifi_data_read_proc(char *page, char **start, off_t off,
 | |
| 					int count, int *eof, void *data)
 | |
| {
 | |
| 	unsigned char *ptr;
 | |
| 
 | |
| 	ptr = get_wifi_nvs_ram();
 | |
| 	memcpy(page, ptr, NVS_DATA_OFFSET);
 | |
| 	return NVS_DATA_OFFSET;
 | |
| }
 | |
| 
 | |
| static int __init wifi_nvs_init(void)
 | |
| {
 | |
| 	pr_info("NVS: wifi_nvs_init\n");
 | |
| #ifdef CONFIG_WIFI_NVS_PROC_CREATE
 | |
| 	wifi_calibration = create_proc_entry("calibration", 0444, NULL);
 | |
| 	if (wifi_calibration != NULL) {
 | |
| 	pr_info("NVS: wifi_calibration\n");
 | |
| 		wifi_calibration->size = wifi_get_nvs_size();
 | |
| 		wifi_calibration->read_proc = wifi_calibration_read_proc;
 | |
| 		wifi_calibration->write_proc = NULL;
 | |
| 	}
 | |
| #endif
 | |
| 	wifi_data = create_proc_entry("wifi_data", 0444, NULL);
 | |
| 	if (wifi_data != NULL) {
 | |
| 		wifi_data->size = NVS_DATA_OFFSET;
 | |
| 		wifi_data->read_proc = wifi_data_read_proc;
 | |
| 		wifi_data->write_proc = NULL;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| late_initcall(wifi_nvs_init);
 |